Merge wpa_supplicant/hostapd 2.4.

Major changes are: SAE, Suite B, RFC 7268, EAP-PKE, ACS, and tons of
bug fixes.

Relnotes:	yes
This commit is contained in:
Rui Paulo 2015-04-21 01:45:11 +00:00
commit 5b9c547c07
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=281806
506 changed files with 105078 additions and 22601 deletions

143
contrib/wpa/CONTRIBUTIONS Normal file
View File

@ -0,0 +1,143 @@
Contributions to hostap.git
---------------------------
This software is distributed under a permissive open source license to
allow it to be used in any projects, whether open source or proprietary.
Contributions to the project are welcome and it is important to maintain
clear record of contributions and terms under which they are licensed.
To help with this, following procedure is used to allow acceptance and
recording of the terms.
All contributions are expected to be licensed under the modified BSD
license (see below). Acknowledgment of the terms is tracked through
inclusion of Signed-off-by tag in the contributions at the end of the
commit log message. This tag indicates that the contributor agrees with
the Developer Certificate of Origin (DCO) version 1.1 terms (see below;
also available from http://developercertificate.org/).
The current requirements for contributions to hostap.git
--------------------------------------------------------
To indicate your acceptance of Developer's Certificate of Origin 1.1
terms, please add the following line to the end of the commit message
for each contribution you make to the project:
Signed-off-by: Your Name <your@email.example.org>
using your real name. Pseudonyms or anonymous contributions cannot
unfortunately be accepted.
History of license and contributions terms
------------------------------------------
Until February 11, 2012, in case of most files in hostap.git, "under the
open source license indicated in the file" means that the contribution
is licensed both under GPL v2 and modified BSD license (see below) and
the choice between these licenses is given to anyone who redistributes
or uses the software. As such, the contribution has to be licensed under
both options to allow this choice.
As of February 11, 2012, the project has chosen to use only the BSD
license option for future distribution. As such, the GPL v2 license
option is no longer used and the contributions are not required to be
licensed until GPL v2. In case of most files in hostap.git, "under the
open source license indicated in the file" means that the contribution
is licensed under the modified BSD license (see below).
Until February 13, 2014, the project used an extended version of the DCO
that included the identical items (a) through (d) from DCO 1.1 and an
additional item (e):
(e) The contribution can be licensed under the modified BSD license
as shown below even in case of files that are currently licensed
under other terms.
This was used during the period when some of the files included the old
license terms. Acceptance of this extended DCO version was indicated
with a Signed-hostap tag in the commit message. This additional item (e)
was used to collect explicit approval to license the contribution with
only the modified BSD license (see below), i.e., without the GPL v2
option. This was done to allow simpler licensing terms to be used in the
future. It should be noted that the modified BSD license is compatible
with GNU GPL and as such, this possible move to simpler licensing option
does not prevent use of this software in GPL projects.
===[ start quote from http://developercertificate.org/ ]=======================
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
===[ end quote from http://developercertificate.org/ ]=========================
The license terms used for hostap.git files
-------------------------------------------
Modified BSD license (no advertisement clause):
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
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -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.

View File

@ -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.
These programs are licensed under the BSD license (the one with

View File

@ -1,5 +1,191 @@
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
* started to use constant time comparison for various password and hash
values to reduce possibility of any externally measurable timing
differences
* extended explicit clearing of freed memory and expired keys to avoid
keeping private data in memory longer than necessary
* added support for number of new RADIUS attributes from RFC 7268
(Mobility-Domain-Id, WLAN-HESSID, WLAN-Pairwise-Cipher,
WLAN-Group-Cipher, WLAN-AKM-Suite, WLAN-Group-Mgmt-Pairwise-Cipher)
* fixed GET_CONFIG wpa_pairwise_cipher value
* added code to clear bridge FDB entry on station disconnection
* fixed PMKSA cache timeout from Session-Timeout for WPA/WPA2 cases
* fixed OKC PMKSA cache entry fetch to avoid a possible infinite loop
in case the first entry does not match
* fixed hostapd_cli action script execution to use more robust mechanism
(CVE-2014-3686)
2014-06-04 - v2.2
* fixed SAE confirm-before-commit validation to avoid a potential
segmentation fault in an unexpected message sequence that could be
triggered remotely
* extended VHT support
- Operating Mode Notification
- Power Constraint element (local_pwr_constraint)
- Spectrum management capability (spectrum_mgmt_required=1)
- fix VHT80 segment picking in ACS
- fix vht_capab 'Maximum A-MPDU Length Exponent' handling
- fix VHT20
* fixed HT40 co-ex scan for some pri/sec channel switches
* extended HT40 co-ex support to allow dynamic channel width changes
during the lifetime of the BSS
* fixed HT40 co-ex support to check for overlapping 20 MHz BSS
* fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding;
this fixes password with include UTF-8 characters that use
three-byte encoding EAP methods that use NtPasswordHash
* reverted TLS certificate validation step change in v2.1 that rejected
any AAA server certificate with id-kp-clientAuth even if
id-kp-serverAuth EKU was included
* fixed STA validation step for WPS ER commands to prevent a potential
crash if an ER sends an unexpected PutWLANResponse to a station that
is disassociated, but not fully removed
* enforce full EAP authentication after RADIUS Disconnect-Request by
removing the PMKSA cache entry
* added support for NAS-IP-Address, NAS-identifier, and NAS-IPv6-Address
in RADIUS Disconnect-Request
* added mechanism for removing addresses for MAC ACLs by prefixing an
entry with "-"
* Interworking/Hotspot 2.0 enhancements
- support Hotspot 2.0 Release 2
* OSEN network for online signup connection
* subscription remediation (based on RADIUS server request or
control interface HS20_WNM_NOTIF for testing purposes)
* Hotspot 2.0 release number indication in WFA RADIUS VSA
* deauthentication request (based on RADIUS server request or
control interface WNM_DEAUTH_REQ for testing purposes)
* Session Info URL RADIUS AVP to trigger ESS Disassociation Imminent
* hs20_icon config parameter to configure icon files for OSU
* osu_* config parameters for OSU Providers list
- do not use Interworking filtering rules on Probe Request if
Interworking is disabled to avoid interop issues
* added/fixed nl80211 functionality
- AP interface teardown optimization
- support vendor specific driver command
(VENDOR <vendor id> <sub command id> [<hex formatted data>])
* fixed PMF protection of Deauthentication frame when this is triggered
by session timeout
* internal TLS implementation enhancements/fixes
- add SHA256-based cipher suites
- add DHE-RSA cipher suites
- fix X.509 validation of PKCS#1 signature to check for extra data
* RADIUS server functionality
- add minimal RADIUS accounting server support (hostapd-as-server);
this is mainly to enable testing coverage with hwsim scripts
- allow authentication log to be written into SQLite databse
- added option for TLS protocol testing of an EAP peer by simulating
various misbehaviors/known attacks
- MAC ACL support for testing purposes
* fixed PTK derivation for CCMP-256 and GCMP-256
* extended WPS per-station PSK to support ER case
* added option to configure the management group cipher
(group_mgmt_cipher=AES-128-CMAC (default), BIP-GMAC-128, BIP-GMAC-256,
BIP-CMAC-256)
* fixed AP mode default TXOP Limit values for AC_VI and AC_VO (these
were rounded incorrectly)
* added support for postponing FT response in case PMK-R1 needs to be
pulled from R0KH
* added option to advertise 40 MHz intolerant HT capability with
ht_capab=[40-INTOLERANT]
* remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled
whenever CONFIG_WPS=y is set
* EAP-pwd fixes
- fix possible segmentation fault on EAP method deinit if an invalid
group is negotiated
* fixed RADIUS client retransmit/failover behavior
- there was a potential ctash due to freed memory being accessed
- failover to a backup server mechanism did not work properly
* fixed a possible crash on double DISABLE command when multiple BSSes
are enabled
* fixed a memory leak in SAE random number generation
* fixed GTK rekeying when the station uses FT protocol
* fixed off-by-one bounds checking in printf_encode()
- this could result in deinial of service in some EAP server cases
* various bug fixes
2014-02-04 - v2.1
* added support for simultaneous authentication of equals (SAE) for
stronger password-based authentication with WPA2-Personal
* added nl80211 functionality
- VHT configuration for nl80211
- support split wiphy dump
- driver-based MAC ACL
- QoS Mapping configuration
* added fully automated regression testing with mac80211_hwsim
* allow ctrl_iface group to be specified on command line (-G<group>)
* allow single hostapd process to control independent WPS interfaces
(wps_independent=1) instead of synchronized operations through all
configured interfaces within a process
* avoid processing received management frames multiple times when using
nl80211 with multiple BSSes
* added support for DFS (processing radar detection events, CAC, channel
re-selection)
* added EAP-EKE server
* added automatic channel selection (ACS)
* added option for using per-BSS (vif) configuration files with
-b<phyname>:<config file name>
* extended global control interface ADD/REMOVE commands to allow BSSes
of a radio to be removed individually without having to add/remove all
other BSSes of the radio at the same time
* added support for sending debug info to Linux tracing (-T on command
line)
* replace dump_file functionality with same information being available
through the hostapd control interface
* added support for using Protected Dual of Public Action frames for
GAS/ANQP exchanges when PMF is enabled
* added support for WPS+NFC updates
- improved protocol
- option to fetch and report alternative carrier records for external
NFC operations
* various bug fixes
2013-01-12 - v2.0
* added AP-STA-DISCONNECTED ctrl_iface event
* improved debug logging (human readable event names, interface name

View File

@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
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
@ -74,12 +74,6 @@ Current hardware/software requirements:
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
madwifi driver for cards based on Atheros chip set (ar521x)
(http://sourceforge.net/projects/madwifi/)
Please note that you will need to add the correct path for
madwifi driver root directory in .config (see defconfig file for
an example: CFLAGS += -I<path>)
mac80211-based drivers that support AP mode (with driver=nl80211).
This includes drivers for Atheros (ath9k) and Broadcom (b43)
chipsets.

View File

@ -58,12 +58,10 @@ hostapd configuration
WPS is an optional component that needs to be enabled in hostapd build
configuration (.config). Here is an example configuration that
includes WPS support and uses madwifi driver interface:
includes WPS support and uses nl80211 driver interface:
CONFIG_DRIVER_MADWIFI=y
CFLAGS += -I/usr/src/madwifi-0.9.3
CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
CONFIG_WPS2=y
CONFIG_WPS_UPNP=y
Following parameter can be used to enable support for NFC config method:
@ -75,8 +73,8 @@ Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
# Configure the driver and network interface
driver=madwifi
interface=ath0
driver=nl80211
interface=wlan0
# WPA2-Personal configuration for the AP
ssid=wps-test
@ -338,3 +336,17 @@ If the NFC tag contains a password token, the token is added to the
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.
"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
contents of a Handover Select Message for connection handover when this
does not depend on the contents of the Handover Request Message. The
first argument selects the format of the output data and the second
argument selects which type of connection handover is requested (WPS =
Wi-Fi handover as specified in WSC 2.0).
"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
<carrier from handover select>" is used to report completed NFC
connection handover. The first parameter indicates whether the local
device initiated or responded to the connection handover and the carrier
records are the selected carrier from the handover request and select
messages as a hexdump.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,13 +15,22 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
# Driver interface for madwifi driver
#CONFIG_DRIVER_MADWIFI=y
#CFLAGS += -I../../madwifi # change to the madwifi source directory
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
#CFLAGS += -I$<path to libnl include files>
#LIBS += -L$<path to libnl library files>
# Use libnl v2.0 (or 3.0) libraries.
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
#CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@ -42,14 +51,14 @@ CONFIG_RSN_PREAUTH=y
CONFIG_PEERKEY=y
# IEEE 802.11w (management frame protection)
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
CONFIG_IEEE80211W=y
# Integrated EAP server
CONFIG_EAP=y
# EAP Re-authentication Protocol (ERP) in integrated EAP server
CONFIG_ERP=y
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
@ -96,16 +105,13 @@ CONFIG_EAP_TTLS=y
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
#CONFIG_EAP_FAST=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable WSC 2.0 support
#CONFIG_WPS2=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# Enable WPS support with NFC config method
@ -117,6 +123,9 @@ CONFIG_EAP_TTLS=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
# EAP-EKE for the integrated EAP server
#CONFIG_EAP_EKE=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@ -132,7 +141,7 @@ CONFIG_IPV6=y
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
@ -154,6 +163,12 @@ CONFIG_IPV6=y
# Disabled by default.
#CONFIG_DEBUG_FILE=y
# Add support for sending all debug messages (regardless of debug verbosity)
# to the Linux kernel tracing facility. This helps debug the entire stack by
# making it easy to record everything happening from the driver up into the
# same file, e.g., using trace-cmd.
#CONFIG_DEBUG_LINUX_TRACING=y
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
@ -171,7 +186,7 @@ CONFIG_IPV6=y
# Note: This requires libnl 3.1 or newer.
#CONFIG_VLAN_NETLINK=y
# Remove support for dumping state into a file on SIGUSR1 signal
# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
@ -267,3 +282,35 @@ CONFIG_IPV6=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
# Testing options
# This can be used to enable some testing options (see also the example
# configuration file) that are really useful only for testing clients that
# connect to this hostapd. These options allow, for example, to drop a
# certain percentage of probe requests or auth/(re)assoc frames.
#
#CONFIG_TESTING_OPTIONS=y
# Automatic Channel Selection
# This will allow hostapd to pick the channel automatically when channel is set
# to "acs_survey" or "0". Eventually, other ACS algorithms can be added in
# similar way.
#
# Automatic selection is currently only done through initialization, later on
# we hope to do background checks to keep us moving to more ideal channels as
# time goes by. ACS is currently only supported through the nl80211 driver and
# your driver must have survey dump capability that is filled by the driver
# during scanning.
#
# You can customize the ACS survey algorithm with the hostapd.conf variable
# acs_num_scans.
#
# Supported ACS drivers:
# * ath9k
# * ath5k
# * ath10k
#
# For more details refer to:
# http://wireless.kernel.org/en/users/Documentation/acs
#
#CONFIG_ACS=y

View File

@ -1,180 +0,0 @@
/*
* hostapd / State dump
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <time.h>
#include "utils/common.h"
#include "radius/radius_client.h"
#include "radius/radius_server.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/sta_info.h"
#include "dump_state.h"
static void fprint_char(FILE *f, char c)
{
if (c >= 32 && c < 127)
fprintf(f, "%c", c);
else
fprintf(f, "<%02x>", c);
}
static void ieee802_1x_dump_state(FILE *f, const char *prefix,
struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
return;
fprintf(f, "%sIEEE 802.1X:\n", prefix);
if (sm->identity) {
size_t i;
fprintf(f, "%sidentity=", prefix);
for (i = 0; i < sm->identity_len; i++)
fprint_char(f, sm->identity[i]);
fprintf(f, "\n");
}
fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
"Supplicant: %d (%s)\n", prefix,
sm->eap_type_authsrv,
eap_server_get_name(0, sm->eap_type_authsrv),
sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
fprintf(f, "%scached_packets=%s\n", prefix,
sm->last_recv_radius ? "[RX RADIUS]" : "");
eapol_auth_dump_state(f, prefix, sm);
}
/**
* hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
*/
static void hostapd_dump_state(struct hostapd_data *hapd)
{
FILE *f;
time_t now;
struct sta_info *sta;
int i;
#ifndef CONFIG_NO_RADIUS
char *buf;
#endif /* CONFIG_NO_RADIUS */
if (!hapd->conf->dump_log_name) {
wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
"request");
return;
}
wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
hapd->conf->dump_log_name);
f = fopen(hapd->conf->dump_log_name, "w");
if (f == NULL) {
wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
"writing.", hapd->conf->dump_log_name);
return;
}
time(&now);
fprintf(f, "hostapd state dump - %s", ctime(&now));
fprintf(f, "num_sta=%d num_sta_non_erp=%d "
"num_sta_no_short_slot_time=%d\n"
"num_sta_no_short_preamble=%d\n",
hapd->num_sta, hapd->iface->num_sta_non_erp,
hapd->iface->num_sta_no_short_slot_time,
hapd->iface->num_sta_no_short_preamble);
for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
fprintf(f,
" AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"\n"
" capability=0x%x listen_interval=%d\n",
sta->aid,
sta->flags,
(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
""),
(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
"[SHORT_PREAMBLE]" : ""),
(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
sta->capability,
sta->listen_interval);
fprintf(f, " supported_rates=");
for (i = 0; i < sta->supported_rates_len; i++)
fprintf(f, "%02x ", sta->supported_rates[i]);
fprintf(f, "\n");
fprintf(f,
" timeout_next=%s\n",
(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
(sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
"DEAUTH")));
ieee802_1x_dump_state(f, " ", sta);
}
#ifndef CONFIG_NO_RADIUS
buf = os_malloc(4096);
if (buf) {
int count = radius_client_get_mib(hapd->radius, buf, 4096);
if (count < 0)
count = 0;
else if (count > 4095)
count = 4095;
buf[count] = '\0';
fprintf(f, "%s", buf);
#ifdef RADIUS_SERVER
count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
if (count < 0)
count = 0;
else if (count > 4095)
count = 4095;
buf[count] = '\0';
fprintf(f, "%s", buf);
#endif /* RADIUS_SERVER */
os_free(buf);
}
#endif /* CONFIG_NO_RADIUS */
fclose(f);
}
int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
hostapd_dump_state(iface->bss[i]);
return 0;
}

View File

@ -1,14 +0,0 @@
/*
* hostapd / State dump
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DUMP_STATE_H
#define DUMP_STATE_H
int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
#endif /* DUMP_STATE_H */

View File

@ -44,6 +44,13 @@ int eap_server_register_methods(void)
ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_TLS
#ifdef CONFIG_HS20
if (ret == 0)
ret = eap_server_wfa_unauth_tls_register();
#endif /* CONFIG_HS20 */
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
@ -134,5 +141,10 @@ int eap_server_register_methods(void)
ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */
#ifdef EAP_SERVER_EKE
if (ret == 0)
ret = eap_server_eke_register();
#endif /* EAP_SERVER_EKE */
return ret;
}

View File

@ -0,0 +1,17 @@
/*
* hostapd module tests
* Copyright (c) 2014, 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"
int hapd_module_tests(void)
{
wpa_printf(MSG_INFO, "hostapd module tests");
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
* Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -18,6 +18,9 @@
* SIM-REQ-AUTH <IMSI> <max_chal>
* SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
* SIM-RESP-AUTH <IMSI> FAILURE
* GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
* GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
* GSM-AUTH-RESP <IMSI> FAILURE
*
* EAP-AKA / UMTS query/response:
* AKA-REQ-AUTH <IMSI>
@ -30,12 +33,16 @@
* IMSI and max_chal are sent as an ASCII string,
* Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
*
* The example implementation here reads GSM authentication triplets from a
* An example implementation here reads GSM authentication triplets from a
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
* for real life authentication, but it is useful both as an example
* implementation and for EAP-SIM/AKA/AKA' testing.
*
* For a stronger example design, Milenage and GSM-Milenage algorithms can be
* used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
* EAP-SIM, respectively, if Ki is known.
*
* SQN generation follows the not time-based Profile 2 described in
* 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
* can be changed with a command line options if needed.
@ -58,6 +65,7 @@ static char *milenage_file = NULL;
static int update_milenage = 0;
static int sqn_changes = 0;
static int ind_len = 5;
static int stdout_debug = 1;
/* GSM triplets */
struct gsm_triplet {
@ -214,6 +222,9 @@ static int db_update_milenage_sqn(struct milenage_parameters *m)
{
char cmd[128], val[13], *pos;
if (sqlite_db == NULL)
return 0;
pos = val;
pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
*pos = '\0';
@ -611,31 +622,30 @@ static struct milenage_parameters * get_milenage(const char *imsi)
}
static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
{
int count, max_chal, ret;
char *pos;
char reply[1000], *rpos, *rend;
char *rpos, *rend;
struct milenage_parameters *m;
struct gsm_triplet *g;
reply[0] = '\0';
resp[0] = '\0';
pos = strchr(imsi, ' ');
if (pos) {
*pos++ = '\0';
max_chal = atoi(pos);
if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
max_chal = EAP_SIM_MAX_CHAL;
} else
max_chal = EAP_SIM_MAX_CHAL;
rend = &reply[sizeof(reply)];
rpos = reply;
rend = resp + resp_len;
rpos = resp;
ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
if (ret < 0 || ret >= rend - rpos)
return;
return -1;
rpos += ret;
m = get_milenage(imsi);
@ -643,7 +653,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
u8 _rand[16], sres[4], kc[8];
for (count = 0; count < max_chal; count++) {
if (random_get_bytes(_rand, 16) < 0)
return;
return -1;
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
*rpos++ = ' ';
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
@ -653,7 +663,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
}
*rpos = '\0';
goto send;
return 0;
}
count = 0;
@ -677,15 +687,61 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
printf("No GSM triplets found for %s\n", imsi);
ret = snprintf(rpos, rend - rpos, " FAILURE");
if (ret < 0 || ret >= rend - rpos)
return;
return -1;
rpos += ret;
}
send:
printf("Send: %s\n", reply);
if (sendto(s, reply, rpos - reply, 0,
(struct sockaddr *) from, fromlen) < 0)
perror("send");
return 0;
}
static int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
{
int count, ret;
char *pos, *rpos, *rend;
struct milenage_parameters *m;
resp[0] = '\0';
pos = os_strchr(imsi, ' ');
if (!pos)
return -1;
*pos++ = '\0';
rend = resp + resp_len;
rpos = resp;
ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
if (os_snprintf_error(rend - rpos, ret))
return -1;
rpos += ret;
m = get_milenage(imsi);
if (m) {
u8 _rand[16], sres[4], kc[8];
for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
if (hexstr2bin(pos, _rand, 16) != 0)
return -1;
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
*rpos++ = count == 0 ? ' ' : ':';
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
*rpos++ = ':';
rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
pos += 16 * 2;
if (*pos != ':')
break;
pos++;
}
*rpos = '\0';
return 0;
}
printf("No GSM triplets found for %s\n", imsi);
ret = os_snprintf(rpos, rend - rpos, " FAILURE");
if (os_snprintf_error(rend - rpos, ret))
return -1;
rpos += ret;
return 0;
}
@ -711,11 +767,10 @@ static void inc_sqn(u8 *sqn)
}
static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
{
/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
char reply[1000], *pos, *end;
char *pos, *end;
u8 _rand[EAP_AKA_RAND_LEN];
u8 autn[EAP_AKA_AUTN_LEN];
u8 ik[EAP_AKA_IK_LEN];
@ -729,16 +784,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
m = get_milenage(imsi);
if (m) {
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
return;
return -1;
res_len = EAP_AKA_RES_MAX_LEN;
inc_sqn(m->sqn);
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
m->sqn[3], m->sqn[4], m->sqn[5]);
if (stdout_debug) {
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
m->sqn[3], m->sqn[4], m->sqn[5]);
}
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
} else {
@ -756,18 +813,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
pos = reply;
end = &reply[sizeof(reply)];
pos = resp;
end = resp + resp_len;
ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
if (ret < 0 || ret >= end - pos)
return;
return -1;
pos += ret;
if (failed) {
ret = snprintf(pos, end - pos, "FAILURE");
if (ret < 0 || ret >= end - pos)
return;
return -1;
pos += ret;
goto done;
return 0;
}
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
@ -779,65 +836,87 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
done:
printf("Send: %s\n", reply);
if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
fromlen) < 0)
perror("send");
return 0;
}
static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
static int aka_auts(char *imsi, char *resp, size_t resp_len)
{
char *auts, *__rand;
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
struct milenage_parameters *m;
resp[0] = '\0';
/* AKA-AUTS <IMSI> <AUTS> <RAND> */
auts = strchr(imsi, ' ');
if (auts == NULL)
return;
return -1;
*auts++ = '\0';
__rand = strchr(auts, ' ');
if (__rand == NULL)
return;
return -1;
*__rand++ = '\0';
printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
if (stdout_debug) {
printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
imsi, auts, __rand);
}
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
printf("Could not parse AUTS/RAND\n");
return;
return -1;
}
m = get_milenage(imsi);
if (m == NULL) {
printf("Unknown IMSI: %s\n", imsi);
return;
return -1;
}
if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
printf("AKA-AUTS: Incorrect MAC-S\n");
} else {
memcpy(m->sqn, sqn, 6);
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
if (stdout_debug) {
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
}
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
}
return 0;
}
static int process_cmd(char *cmd, char *resp, size_t resp_len)
{
if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
return sim_req_auth(cmd + 13, resp, resp_len);
if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
return gsm_auth_req(cmd + 13, resp, resp_len);
if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
return aka_req_auth(cmd + 13, resp, resp_len);
if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
return aka_auts(cmd + 9, resp, resp_len);
printf("Unknown request: %s\n", cmd);
return -1;
}
static int process(int s)
{
char buf[1000];
char buf[1000], resp[1000];
struct sockaddr_un from;
socklen_t fromlen;
ssize_t res;
@ -859,14 +938,21 @@ static int process(int s)
printf("Received: %s\n", buf);
if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
sim_req_auth(s, &from, fromlen, buf + 13);
else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
aka_req_auth(s, &from, fromlen, buf + 13);
else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
aka_auts(s, &from, fromlen, buf + 9);
else
printf("Unknown request: %s\n", buf);
if (process_cmd(buf, resp, sizeof(resp)) < 0) {
printf("Failed to process request\n");
return -1;
}
if (resp[0] == '\0') {
printf("No response\n");
return 0;
}
printf("Send: %s\n", resp);
if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
fromlen) < 0)
perror("send");
return 0;
}
@ -894,8 +980,10 @@ static void cleanup(void)
os_free(prev);
}
close(serv_sock);
unlink(socket_path);
if (serv_sock >= 0)
close(serv_sock);
if (socket_path)
unlink(socket_path);
#ifdef CONFIG_SQLITE
if (sqlite_db) {
@ -917,12 +1005,12 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
"Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
"Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
" [-D<DB file>] [-i<IND len in bits>]\n"
" [-D<DB file>] [-i<IND len in bits>] [command]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
@ -932,7 +1020,15 @@ static void usage(void)
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n"
" -D<DB file> = path to SQLite database\n"
" -i<IND len in bits> = IND length for SQN (default: 5)\n",
" -i<IND len in bits> = IND length for SQN (default: 5)\n"
"\n"
"If the optional command argument, like "
"\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
"command is processed with response sent to stdout. Otherwise, "
"hlr_auc_gw opens\n"
"a control interface and processes commands sent through it "
"(e.g., by EAP server\n"
"in hostapd).\n",
default_socket_path);
}
@ -942,6 +1038,7 @@ int main(int argc, char *argv[])
int c;
char *gsm_triplet_file = NULL;
char *sqlite_db_file = NULL;
int ret = 0;
if (os_program_init())
return -1;
@ -1005,18 +1102,31 @@ int main(int argc, char *argv[])
if (milenage_file && read_milenage(milenage_file) < 0)
return -1;
serv_sock = open_socket(socket_path);
if (serv_sock < 0)
return -1;
if (optind == argc) {
serv_sock = open_socket(socket_path);
if (serv_sock < 0)
return -1;
printf("Listening for requests on %s\n", socket_path);
printf("Listening for requests on %s\n", socket_path);
atexit(cleanup);
signal(SIGTERM, handle_term);
signal(SIGINT, handle_term);
atexit(cleanup);
signal(SIGTERM, handle_term);
signal(SIGINT, handle_term);
for (;;)
process(serv_sock);
for (;;)
process(serv_sock);
} else {
char buf[1000];
socket_path = NULL;
stdout_debug = 0;
if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
printf("FAIL\n");
ret = -1;
} else {
printf("%s\n", buf);
}
cleanup();
}
#ifdef CONFIG_SQLITE
if (sqlite_db) {
@ -1027,5 +1137,5 @@ int main(int argc, char *argv[])
os_program_deinit();
return 0;
return ret;
}

View File

@ -12,7 +12,7 @@ daemon.
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211).
.B hostapd
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.

View File

@ -2,10 +2,10 @@
# Empty lines and lines starting with # are ignored
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
# management frames); ath0 for madwifi
# management frames with the Host AP driver); wlan0 with many nl80211 drivers
interface=wlan0
# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
# In case of atheros and nl80211 driver interfaces, an additional
# configuration parameter, bridge, may be used to notify hostapd if the
# interface is included in a bridge. This parameter is not used with Host AP
# driver. If the bridge parameter is not set, the drivers will automatically
@ -18,12 +18,15 @@ interface=wlan0
# interface is also created.
#bridge=br0
# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
# Driver interface type (hostap/wired/none/nl80211/bsd);
# default: hostap). nl80211 is used with all Linux mac80211 drivers.
# Use driver=none if building hostapd as a standalone RADIUS server that does
# not control any wireless/wired driver.
# driver=hostap
# Driver interface parameters (mainly for development testing use)
# driver_params=<params>
# hostapd event logger configuration
#
# Two output method: syslog and stdout (only usable if not forking to
@ -51,9 +54,6 @@ logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
# Dump file for state information (on SIGUSR1)
dump_file=/tmp/hostapd.dump
# Interface for separate control program. If this is specified, hostapd
# will create this directory and a UNIX domain socket for listening to requests
# from external programs (CLI/GUI, etc.) for status information and
@ -105,6 +105,26 @@ ssid=test
# (default: 0 = disabled)
#ieee80211d=1
# Enable IEEE 802.11h. This enables radar detection and DFS support if
# available. DFS support is required on outdoor 5 GHz channels in most countries
# of the world. This can be used only with ieee80211d=1.
# (default: 0 = disabled)
#ieee80211h=1
# Add Power Constraint element to Beacon and Probe Response frames
# This config option adds Power Constraint element when applicable and Country
# element is added. Power Constraint element is required by Transmit Power
# Control. This can be used only with ieee80211d=1.
# Valid values are 0..255.
#local_pwr_constraint=3
# Set Spectrum Management subfield in the Capability Information field.
# This config option forces the Spectrum Management bit to be set. When this
# option is not set, the value of the Spectrum Management bit depends on whether
# DFS or TPC is required by regulatory authorities. This can be used only with
# ieee80211d=1 and local_pwr_constraint configured.
#spectrum_mgmt_required=1
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
# specify band)
@ -115,8 +135,44 @@ hw_mode=g
# (default: 0, i.e., not set)
# Please note that some drivers do not use this value from hostapd and the
# channel will need to be configured separately with iwconfig.
#
# If CONFIG_ACS build option is enabled, the channel can be selected
# automatically at run time by setting channel=acs_survey or channel=0, both of
# which will enable the ACS survey based algorithm.
channel=1
# ACS tuning - Automatic Channel Selection
# See: http://wireless.kernel.org/en/users/Documentation/acs
#
# You can customize the ACS survey algorithm with following variables:
#
# acs_num_scans requirement is 1..100 - number of scans to be performed that
# are used to trigger survey data gathering of an underlying device driver.
# Scans are passive and typically take a little over 100ms (depending on the
# driver) on each available channel for given hw_mode. Increasing this value
# means sacrificing startup time and gathering more data wrt channel
# 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.
# Default: not set (allow any enabled channel to be selected)
#chanlist=100 104 108 112 116
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@ -176,7 +232,7 @@ fragm_threshold=2346
# Station MAC address -based authentication
# Please note that this kind of access control requires a driver that uses
# hostapd to take care of management frame processing and as such, this can be
# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
# used with driver=hostap or driver=nl80211, but not with driver=atheros.
# 0 = accept unless in deny list
# 1 = deny unless in accept list
# 2 = use external RADIUS server (accept/deny lists are searched first)
@ -383,10 +439,24 @@ wmm_ac_vo_acm=0
# use a separate bridge.
#wds_bridge=wds-br0
# Start the AP with beaconing disabled by default.
#start_disabled=0
# Client isolation can be used to prevent low-level bridging of frames between
# associated stations in the BSS. By default, this bridging is allowed.
#ap_isolate=1
# BSS Load update period (in BUs)
# This field is used to enable and configure adding a BSS Load element into
# Beacon and Probe Response frames.
#bss_load_update_period=50
# Fixed BSS Load value for testing purposes
# This field can be used to configure hostapd to add a fixed BSS Load element
# into Beacon and Probe Response frames for testing purposes. The format is
# <station count>:<channel utilization>:<available admission capacity>
#bss_load_test=12:80:20000
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@ -399,7 +469,7 @@ wmm_ac_vo_acm=0
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
# with secondary channel below the primary channel
# with secondary channel above the primary channel
# (20 MHz only if neither is set)
# Note: There are limits on which channels can be used with HT40- and
# HT40+. Following table shows the channels that may be available for
@ -426,13 +496,20 @@ wmm_ac_vo_acm=0
# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
# set)
# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
# PSMP support: [PSMP] (disabled if not set)
# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set)
# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
# Require stations to support HT PHY (reject association if they do not)
#require_ht=1
# 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. 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 #####################################
# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
@ -627,6 +704,17 @@ eapol_key_index_workaround=0
# is only used by one station.
#use_pae_group_addr=1
# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
#
# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
# EAP-Identity/Request
#erp_send_reauth_start=1
#
# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
# set (no local ER server). This is also used by the integrated EAP server if
# ERP is enabled (eap_server_erp=1).
#erp_domain=example.com
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
@ -660,6 +748,11 @@ eap_server=0
# Passphrase for private key
#private_key_passwd=secret passphrase
# Server identity
# EAP methods that provide mechanism for authenticated server identity delivery
# use this value. If not set, "hostapd" is used as a default.
#server_id=server.example.com
# Enable CRL verification.
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
# valid CRL signed by the CA is required to be included in the ca_cert file.
@ -671,6 +764,20 @@ eap_server=0
# 2 = check all CRLs in the certificate path
#check_crl=1
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
# This cache file can be updated, e.g., by running following command
# periodically to get an update from the OCSP responder:
# openssl ocsp \
# -no_nonce \
# -CAfile /etc/hostapd.ca.pem \
# -issuer /etc/hostapd.ca.pem \
# -cert /etc/hostapd.server.pem \
# -url http://ocsp.example.com:8888/ \
# -respout /tmp/ocsp-cache.der
#ocsp_stapling_response=/tmp/ocsp-cache.der
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA authentication does
@ -683,6 +790,15 @@ eap_server=0
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
#dh_file=/etc/hostapd.dh.pem
# OpenSSL cipher string
#
# This is an OpenSSL specific configuration option for configuring the default
# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
# on cipher suite configuration. This is applicable only if hostapd is built to
# use OpenSSL.
#openssl_ciphers=DEFAULT:!EXP:!LOW
# Fragment size for EAP methods
#fragment_size=1400
@ -744,6 +860,10 @@ eap_server=0
# EAP method is enabled, the peer will be allowed to connect without TNC.
#tnc=1
# EAP Re-authentication Protocol (ERP) - RFC 6696
#
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
@ -765,6 +885,12 @@ own_ip_addr=127.0.0.1
# 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
@ -814,9 +940,8 @@ own_ip_addr=127.0.0.1
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). vlan_file option below must be configured if dynamic
# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
# used to set static client MAC address to VLAN ID mapping.
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
# 0 = disabled (default)
# 1 = option; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
@ -828,6 +953,8 @@ own_ip_addr=127.0.0.1
# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
# interface and the line must include VLAN ID and interface name separated by
# white space (space or tab).
# If no entries are provided by this file, the station is statically mapped
# to <bss-iface>.<vlan-id> interfaces.
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@ -837,6 +964,12 @@ own_ip_addr=127.0.0.1
# to the bridge.
#vlan_tagged_interface=eth0
# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
# and br%s.%d if a tagged interface is given, provided %s = tagged interface
# and %d = VLAN ID.
#vlan_bridge=brvlan
# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
# to know how to name it.
# 0 = vlan<XXX>, e.g., vlan1
@ -906,6 +1039,11 @@ own_ip_addr=127.0.0.1
# The UDP port number for the RADIUS authentication server
#radius_server_auth_port=1812
# The UDP port number for the RADIUS accounting server
# Commenting this out or setting this to 0 can be used to disable RADIUS
# accounting while still enabling RADIUS authentication.
#radius_server_acct_port=1813
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
#radius_server_ipv6=1
@ -1012,6 +1150,17 @@ own_ip_addr=127.0.0.1
# 2 = required
#ieee80211w=0
# Group management cipher suite
# Default: AES-128-CMAC (BIP)
# Other options (depending on driver support):
# BIP-GMAC-128
# BIP-GMAC-256
# BIP-CMAC-256
# Note: All the stations connecting to the BSS will also need to support the
# selected cipher. The default AES-128-CMAC is the only option that is commonly
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@ -1037,6 +1186,19 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#okc=1
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
#sae_anti_clogging_threshold=5
# Enabled SAE finite cyclic groups
# SAE implementation are required to support group 19 (ECC group defined over a
# 256-bit prime order field). All groups that are supported by the
# implementation are enabled by default. This configuration parameter can be
# used to specify a limited set of allowed groups. The group values are listed
# in the IANA registry:
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
#sae_groups=19 20 21 25 26
##### IEEE 802.11r configuration ##############################################
@ -1111,6 +1273,14 @@ own_ip_addr=127.0.0.1
# 2 = WPS enabled, configured
#wps_state=2
# Whether to manage this interface independently from other WPS interfaces
# By default, a single hostapd process applies WPS operations to all configured
# interfaces. This parameter can be used to disable that behavior for a subset
# of interfaces. If this is set to non-zero for an interface, WPS commands
# issued on that interface do not apply to other interfaces and WPS operations
# performed on other interfaces do not affect this interface.
#wps_independent=0
# AP can be configured into a locked state where new WPS Registrar are not
# accepted, but previously authorized Registrars (including the internal one)
# can continue to add new Enrollees.
@ -1315,6 +1485,11 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#bss_transition=1
# Proxy ARP
# 0 = disabled (default)
# 1 = enabled
#proxy_arp=1
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
@ -1381,6 +1556,9 @@ own_ip_addr=127.0.0.1
# information to be complete.
#venue_name=eng:Example venue
#venue_name=fin:Esimerkkipaikka
# Alternative format for language:value strings:
# (double quoted string, printf-escaped string)
#venue_name=P"eng:Example\nvenue"
# Network Authentication Type
# This parameter indicates what type of network authentication is used in the
@ -1432,6 +1610,8 @@ own_ip_addr=127.0.0.1
# accordance with IETF RFC 4282
# NAI Realm(s): Semi-colon delimited NAI Realm(s)
# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
# EAP Method types, see:
# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4
# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
# ID 2 = Non-EAP Inner Authentication Type
# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
@ -1445,6 +1625,23 @@ own_ip_addr=127.0.0.1
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
# QoS Map Set configuration
#
# Comma delimited QoS Map Set in decimal values
# (see IEEE Std 802.11-2012, 8.4.2.97)
#
# format:
# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
#
# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
# each UP starting from 0. If both low and high value are set to 255, the
# corresponding UP is not used.
#
# default: not set
#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
##### Hotspot 2.0 #############################################################
# Enable Hotspot 2.0 support
@ -1457,6 +1654,21 @@ own_ip_addr=127.0.0.1
# forging such frames to other stations in the BSS.
#disable_dgaf=1
# OSU Server-Only Authenticated L2 Encryption Network
#osen=1
# ANQP Domain ID (0..65535)
# An identifier for a set of APs in an ESS that share the same common ANQP
# information. 0 = Some of the ANQP information is unique to this AP (default).
#anqp_domain_id=1234
# Deauthentication request timeout
# If the RADIUS server indicates that the station is not allowed to connect to
# the BSS/ESS, the AP can allow the station some time to download a
# notification page (URL included in the message). This parameter sets that
# timeout in seconds.
#hs20_deauth_req_timeout=60
# Operator Friendly Name
# This parameter can be used to configure one or more Operator Friendly Name
# Duples. Each entry has a two or three character language code (ISO-639)
@ -1500,6 +1712,54 @@ own_ip_addr=127.0.0.1
# channels 36-48):
#hs20_operating_class=5173
# OSU icons
# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
# OSU SSID (see ssid2 for format description)
# This is the SSID used for all OSU connections to all the listed OSU Providers.
#osu_ssid="example"
# OSU Providers
# One or more sets of following parameter. Each OSU provider is started by the
# mandatory osu_server_uri item. The other parameters add information for the
# last added OSU provider.
#
#osu_server_uri=https://example.com/osu/
#osu_friendly_name=eng:Example operator
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
#osu_nai=anonymous@example.com
#osu_method_list=1 0
#osu_icon=icon32
#osu_icon=icon64
#osu_service_desc=eng:Example services
#osu_service_desc=fin:Esimerkkipalveluja
#
#osu_server_uri=...
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
# testing some scenarios that are otherwise difficult to reproduce.
#
# Ignore probe requests sent to hostapd with the given probability, must be a
# floating point number in the range [0, 1).
#ignore_probe_probability=0.0
#
# Ignore authentication frames with the given probability
#ignore_auth_probability=0.0
#
# Ignore association requests with the given probability
#ignore_assoc_probability=0.0
#
# Ignore reassociation requests with the given probability
#ignore_reassoc_probability=0.0
#
# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
#corrupt_gtk_rekey_mic_probability=0.0
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
@ -1521,6 +1781,11 @@ own_ip_addr=127.0.0.1
# - is not the same as the MAC address of the radio
# - is not the same as any other explicitly specified BSSID
#
# Not all drivers support multiple BSSes. The exact mechanism for determining
# the driver capabilities is driver specific. With the current (i.e., a recent
# kernel) drivers using nl80211, this information can be checked with "iw list"
# (search for "valid interface combinations").
#
# Please note that hostapd uses some of the values configured for the first BSS
# as the defaults for the following BSSes. However, it is recommended that all
# BSSes include explicit configuration of all relevant configuration items.

View File

@ -48,6 +48,12 @@
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
# hash.
#
# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly
# to the way radius_auth_req_attr is used for Access-Request packet in
# hostapd.conf. For EAP server, this is configured separately for each user
# entry with radius_accept_attr=<value> line(s) following the main user entry
# line.
# Phase 1 users
"user" MD5 "password"

View File

@ -2,6 +2,7 @@ CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
remediation TEXT,
phase2 INTEGER
);
@ -15,3 +16,11 @@ INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 use
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
CREATE TABLE authlog(
timestamp TEXT,
session TEXT,
nas_ip TEXT,
username TEXT,
note TEXT
);

View File

@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
* Copyright (c) 2004-2012, 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.
@ -18,7 +18,7 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
@ -79,6 +79,7 @@ static const char *commands_help =
#endif /* CONFIG_WPS_NFC */
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
" wps_config <SSID> <auth> <encr> <key> configure AP\n"
" wps_get_status show current WPS status\n"
#endif /* CONFIG_WPS */
" get_config show current configuration\n"
" help show this usage help\n"
@ -90,7 +91,12 @@ static const char *commands_help =
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
static int hostapd_cli_attached = 0;
static const char *ctrl_iface_dir = "/var/run/hostapd";
#ifndef CONFIG_CTRL_IFACE_DIR
#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
#endif /* CONFIG_CTRL_IFACE_DIR */
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
@ -210,8 +216,21 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
return wpa_ctrl_command(ctrl, "STATUS");
}
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc > 0) {
char buf[100];
os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
return wpa_ctrl_command(ctrl, "MIB");
}
@ -219,28 +238,19 @@ static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int hostapd_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
char *cmd;
char *arg;
size_t len;
int res;
int ret = 0;
len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
cmd = os_malloc(len);
if (cmd == NULL)
len = os_strlen(arg1) + os_strlen(arg2) + 2;
arg = os_malloc(len);
if (arg == NULL)
return -1;
res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
if (res < 0 || (size_t) res >= len) {
os_free(cmd);
return -1;
}
cmd[len - 1] = '\0';
#ifndef _WIN32_WCE
if (system(cmd) < 0)
ret = -1;
#endif /* _WIN32_WCE */
os_free(cmd);
os_snprintf(arg, len, "%s %s", arg1, arg2);
res = os_exec(program, arg, 1);
os_free(arg);
return ret;
return res;
}
@ -264,12 +274,15 @@ static void hostapd_cli_action_process(char *msg, size_t len)
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char buf[64];
if (argc != 1) {
printf("Invalid 'sta' command - exactly one argument, STA "
if (argc < 1) {
printf("Invalid 'sta' command - at least one argument, STA "
"address, is required.\n");
return -1;
}
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
if (argc > 1)
snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
else
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
@ -380,7 +393,7 @@ static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
else
res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_CHECK_PIN command.\n");
return -1;
}
@ -443,7 +456,7 @@ static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
return -1;
}
@ -464,12 +477,35 @@ static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
}
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_TOKEN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char cmd[64];
int res;
if (argc != 2) {
printf("Invalid 'nfc_get_handover_sel' command - two arguments "
"are required.\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
argv[0], argv[1]);
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long NFC_GET_HANDOVER_SEL command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
#endif /* CONFIG_WPS_NFC */
@ -494,6 +530,13 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
}
static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@ -553,7 +596,7 @@ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
argv[0], argv[1]);
if (res < 0 || res >= (int) sizeof(buf))
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@ -565,20 +608,47 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
char buf[300];
int res;
if (argc < 2) {
printf("Invalid 'ess_disassoc' command - two arguments (STA "
"addr and URL) are needed\n");
if (argc < 3) {
printf("Invalid 'ess_disassoc' command - three arguments (STA "
"addr, disassoc timer, and URL) are needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
argv[0], argv[1]);
if (res < 0 || res >= (int) sizeof(buf))
res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
argv[0], argv[1], argv[2]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[2000], *tmp;
int res, i, total;
if (argc < 1) {
printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
total = res;
for (i = 1; i < argc; i++) {
tmp = &buf[total];
res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
if (os_snprintf_error(sizeof(buf) - total, res))
return -1;
total += res;
}
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@ -652,6 +722,90 @@ static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char buf[200];
int res;
if (argc != 1) {
printf("Invalid 'set_qos_map_set' command - "
"one argument (comma delimited QoS map set) "
"is needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char buf[50];
int res;
if (argc != 1) {
printf("Invalid 'send_qos_map_conf' command - "
"one argument (STA addr) is needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[300];
int res;
if (argc < 2) {
printf("Invalid 'hs20_wnm_notif' command - two arguments (STA "
"addr and URL) are needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
argv[0], argv[1]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[300];
int res;
if (argc < 3) {
printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n");
return -1;
}
if (argc > 3)
res = os_snprintf(buf, sizeof(buf),
"HS20_DEAUTH_REQ %s %s %s %s",
argv[0], argv[1], argv[2], argv[3]);
else
res = os_snprintf(buf, sizeof(buf),
"HS20_DEAUTH_REQ %s %s %s",
argv[0], argv[1], argv[2]);
if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
@ -706,8 +860,10 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
}
hostapd_cli_close_connection();
free(ctrl_ifname);
ctrl_ifname = strdup(argv[0]);
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(argv[0]);
if (ctrl_ifname == NULL)
return -1;
if (hostapd_cli_open_connection(ctrl_ifname)) {
printf("Connected to interface '%s.\n", ctrl_ifname);
@ -737,7 +893,7 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long SET command.\n");
return -1;
}
@ -757,7 +913,7 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long GET command.\n");
return -1;
}
@ -765,6 +921,94 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char cmd[256];
int res;
int i;
char *tmp;
int total;
if (argc < 2) {
printf("Invalid chan_switch command: needs at least two "
"arguments (count and freq)\n"
"usage: <cs_count> <freq> [sec_channel_offset=] "
"[center_freq1=] [center_freq2=] [bandwidth=] "
"[blocktx] [ht|vht]\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
argv[0], argv[1]);
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long CHAN_SWITCH command.\n");
return -1;
}
total = res;
for (i = 2; i < argc; i++) {
tmp = cmd + total;
res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
if (os_snprintf_error(sizeof(cmd) - total, res)) {
printf("Too long CHAN_SWITCH command.\n");
return -1;
}
total += res;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "ENABLE");
}
static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "RELOAD");
}
static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "DISABLE");
}
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc < 2 || argc > 3) {
printf("Invalid vendor command\n"
"usage: <vendor id> <command id> [<hex formatted command argument>]\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
argc == 3 ? argv[2] : "");
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "ERP_FLUSH");
}
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@ -774,6 +1018,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
{ "status", hostapd_cli_cmd_status },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
@ -791,12 +1036,15 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
{ "wps_get_status", hostapd_cli_cmd_wps_get_status },
#endif /* CONFIG_WPS */
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
{ "interface", hostapd_cli_cmd_interface },
@ -805,6 +1053,16 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "quit", hostapd_cli_cmd_quit },
{ "set", hostapd_cli_cmd_set },
{ "get", hostapd_cli_cmd_get },
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
{ "chan_switch", hostapd_cli_cmd_chan_switch },
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
{ "vendor", hostapd_cli_cmd_vendor },
{ "enable", hostapd_cli_cmd_enable },
{ "reload", hostapd_cli_cmd_reload },
{ "disable", hostapd_cli_cmd_disable },
{ "erp_flush", hostapd_cli_cmd_erp_flush },
{ NULL, NULL }
};

View File

@ -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.
@ -9,10 +9,12 @@
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <syslog.h>
#include <grp.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
@ -24,17 +26,9 @@
#include "ap/ap_drv_ops.h"
#include "config_file.h"
#include "eap_register.h"
#include "dump_state.h"
#include "ctrl_iface.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
extern struct wpa_driver_ops *wpa_drivers[];
struct hapd_global {
void **drv_priv;
size_t drv_count;
@ -98,22 +92,24 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
if (hapd && hapd->conf && addr)
os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
hapd->conf->iface, MAC2STR(addr),
module_str ? " " : "", module_str, txt);
module_str ? " " : "", module_str ? module_str : "",
txt);
else if (hapd && hapd->conf)
os_snprintf(format, maxlen, "%s:%s%s %s",
hapd->conf->iface, module_str ? " " : "",
module_str, txt);
module_str ? module_str : "", txt);
else if (addr)
os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
MAC2STR(addr), module_str ? " " : "",
module_str, txt);
module_str ? module_str : "", txt);
else
os_snprintf(format, maxlen, "%s%s%s",
module_str, module_str ? ": " : "", txt);
module_str ? module_str : "",
module_str ? ": " : "", txt);
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
printf("%s\n", format);
wpa_printf(MSG_INFO, "%s", format);
}
#ifndef CONFIG_NATIVE_WINDOWS
@ -147,63 +143,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
* Returns: Pointer to the allocated interface data or %NULL on failure
*
* This function is used to allocate main data structures for per-interface
* data. The allocated data buffer will be freed by calling
* hostapd_cleanup_iface().
* hostapd_driver_init - Preparate driver interface
*/
static struct hostapd_iface * hostapd_init(const char *config_file)
{
struct hostapd_iface *hapd_iface = NULL;
struct hostapd_config *conf = NULL;
struct hostapd_data *hapd;
size_t i;
hapd_iface = os_zalloc(sizeof(*hapd_iface));
if (hapd_iface == NULL)
goto fail;
hapd_iface->config_fname = os_strdup(config_file);
if (hapd_iface->config_fname == NULL)
goto fail;
conf = hostapd_config_read(hapd_iface->config_fname);
if (conf == NULL)
goto fail;
hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss;
hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
goto fail;
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf,
&conf->bss[i]);
if (hapd == NULL)
goto fail;
hapd->msg_ctx = hapd;
}
return hapd_iface;
fail:
if (conf)
hostapd_config_free(conf);
if (hapd_iface) {
os_free(hapd_iface->config_fname);
os_free(hapd_iface->bss);
os_free(hapd_iface);
}
return NULL;
}
static int hostapd_driver_init(struct hostapd_iface *iface)
{
struct wpa_init_params params;
@ -243,9 +184,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
params.bssid = b;
params.ifname = hapd->conf->iface;
params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.test_socket = hapd->conf->test_socket;
params.driver_params = hapd->iconf->driver_params;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
@ -271,14 +210,35 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
if (hapd->driver->get_capa &&
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
if (triggs && hapd->driver->set_wowlan) {
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
wpa_printf(MSG_ERROR, "set_wowlan failed");
}
os_free(triggs);
}
return 0;
}
/**
* hostapd_interface_init - Read configuration file and init BSS data
*
* This function is used to parse configuration file for a full interface (one
* or more BSSes sharing the same radio) and allocate memory for the BSS
* interfaces. No actiual driver operations are started.
*/
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@ -287,7 +247,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
int k;
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
iface = hostapd_init(config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
iface->interfaces = interfaces;
@ -297,13 +257,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface->bss[0]->conf->logger_stdout_level--;
}
if (iface->conf->bss[0].iface[0] != 0 ||
hostapd_drv_none(iface->bss[0])) {
if (hostapd_driver_init(iface) ||
hostapd_setup_interface(iface)) {
hostapd_interface_deinit_free(iface);
return NULL;
}
if (iface->conf->bss[0]->iface[0] == '\0' &&
!hostapd_drv_none(iface->bss[0])) {
wpa_printf(MSG_ERROR, "Interface name not specified in %s",
config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
}
return iface;
@ -346,10 +305,7 @@ static void handle_reload(int sig, void *signal_ctx)
static void handle_dump_state(int sig, void *signal_ctx)
{
#ifdef HOSTAPD_DUMP_STATE
struct hapd_interfaces *interfaces = signal_ctx;
hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
#endif /* HOSTAPD_DUMP_STATE */
/* Not used anymore - ignore signal */
}
#endif /* CONFIG_NATIVE_WINDOWS */
@ -452,7 +408,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
#endif /* EAP_SERVER_TNC */
if (daemonize && os_daemonize(pid_file)) {
perror("daemon");
wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
@ -468,7 +424,7 @@ static void show_version(void)
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
"Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@ -480,7 +436,8 @@ static void usage(void)
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
" [-g <global ctrl_iface>] <configuration file(s)>\n"
" [-g <global ctrl_iface>] [-G <group>] \\\n"
" <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
@ -488,11 +445,16 @@ static void usage(void)
" -B run daemon in the background\n"
" -e entropy file\n"
" -g global control interface path\n"
" -G group for control interfaces\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_LINUX_TRACING
" -T = record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@ -503,8 +465,9 @@ static void usage(void)
static const char * hostapd_msg_ifname_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
if (hapd && hapd->iconf && hapd->iconf->bss)
return hapd->iconf->bss->iface;
if (hapd && hapd->iconf && hapd->iconf->bss &&
hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
return hapd->iconf->bss[0]->iface;
return NULL;
}
@ -519,6 +482,8 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
return -1;
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "No '/' in the global control interface "
"file");
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
return -1;
@ -531,15 +496,57 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
}
static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
const char *group)
{
#ifndef CONFIG_NATIVE_WINDOWS
struct group *grp;
grp = getgrnam(group);
if (grp == NULL) {
wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
return -1;
}
interfaces->ctrl_iface_group = grp->gr_gid;
#endif /* CONFIG_NATIVE_WINDOWS */
return 0;
}
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
{
u8 addr[ETH_ALEN];
u8 uuid[UUID_LEN];
char buf[100];
if (hwaddr_aton(txt_addr, addr) < 0)
return -1;
uuid_gen_mac_addr(addr, uuid);
if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
return -1;
printf("%s\n", buf);
return 0;
}
#endif /* CONFIG_WPS */
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
int ret = 1;
size_t i;
size_t i, j;
int c, debug = 0, daemonize = 0;
char *pid_file = NULL;
const char *log_file = NULL;
const char *entropy_file = NULL;
char **bss_config = NULL, **tmp_bss;
size_t num_bss_configs = 0;
#ifdef CONFIG_DEBUG_LINUX_TRACING
int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
if (os_program_init())
return -1;
@ -556,7 +563,7 @@ int main(int argc, char *argv[])
interfaces.global_ctrl_sock = -1;
for (;;) {
c = getopt(argc, argv, "Bde:f:hKP:tvg:");
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
if (c < 0)
break;
switch (c) {
@ -587,31 +594,65 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
#ifdef CONFIG_DEBUG_LINUX_TRACING
case 'T':
enable_trace_dbg = 1;
break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 'v':
show_version();
exit(1);
break;
case 'g':
hostapd_get_global_ctrl_iface(&interfaces, optarg);
if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
return -1;
break;
case 'G':
if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
return -1;
break;
case 'b':
tmp_bss = os_realloc_array(bss_config,
num_bss_configs + 1,
sizeof(char *));
if (tmp_bss == NULL)
goto out;
bss_config = tmp_bss;
bss_config[num_bss_configs++] = optarg;
break;
#ifdef CONFIG_WPS
case 'u':
return gen_uuid(optarg);
#endif /* CONFIG_WPS */
default:
usage();
break;
}
}
if (optind == argc && interfaces.global_iface_path == NULL)
if (optind == argc && interfaces.global_iface_path == NULL &&
num_bss_configs == 0)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
if (log_file)
wpa_debug_open_file(log_file);
else
wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (enable_trace_dbg) {
int tret = wpa_debug_open_linux_tracing();
if (tret) {
wpa_printf(MSG_ERROR, "Failed to enable trace logging");
return -1;
}
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
interfaces.count = argc - optind;
if (interfaces.count) {
interfaces.iface = os_calloc(interfaces.count,
if (interfaces.count || num_bss_configs) {
interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
sizeof(struct hostapd_iface *));
if (interfaces.iface == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
@ -619,30 +660,93 @@ int main(int argc, char *argv[])
}
}
if (hostapd_global_init(&interfaces, entropy_file))
if (hostapd_global_init(&interfaces, entropy_file)) {
wpa_printf(MSG_ERROR, "Failed to initilize global context");
return -1;
}
/* Initialize interfaces */
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
interfaces.iface[i] = hostapd_interface_init(&interfaces,
argv[optind + i],
debug);
if (!interfaces.iface[i])
if (!interfaces.iface[i]) {
wpa_printf(MSG_ERROR, "Failed to initialize interface");
goto out;
}
}
/* Allocate and parse configuration for per-BSS files */
for (i = 0; i < num_bss_configs; i++) {
struct hostapd_iface *iface;
char *fname;
wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
fname = os_strchr(bss_config[i], ':');
if (fname == NULL) {
wpa_printf(MSG_ERROR,
"Invalid BSS config identifier '%s'",
bss_config[i]);
goto out;
}
*fname++ = '\0';
iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
fname, debug);
if (iface == NULL)
goto out;
for (j = 0; j < interfaces.count; j++) {
if (interfaces.iface[j] == iface)
break;
}
if (j == interfaces.count) {
struct hostapd_iface **tmp;
tmp = os_realloc_array(interfaces.iface,
interfaces.count + 1,
sizeof(struct hostapd_iface *));
if (tmp == NULL) {
hostapd_interface_deinit_free(iface);
goto out;
}
interfaces.iface = tmp;
interfaces.iface[interfaces.count++] = iface;
}
}
/*
* Enable configured interfaces. Depending on channel configuration,
* this may complete full initialization before returning or use a
* callback mechanism to complete setup in case of operations like HT
* co-ex scans, ACS, or DFS are needed to determine channel parameters.
* In such case, the interface will be enabled from eloop context within
* hostapd_global_run().
*/
interfaces.terminate_on_error = interfaces.count;
for (i = 0; i < interfaces.count; i++) {
if (hostapd_driver_init(interfaces.iface[i]) ||
hostapd_setup_interface(interfaces.iface[i]))
goto out;
}
hostapd_global_ctrl_iface_init(&interfaces);
if (hostapd_global_run(&interfaces, daemonize, pid_file))
if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
wpa_printf(MSG_ERROR, "Failed to start eloop");
goto out;
}
ret = 0;
out:
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++)
for (i = 0; i < interfaces.count; i++) {
if (!interfaces.iface[i])
continue;
interfaces.iface[i]->driver_ap_teardown =
!!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]);
}
os_free(interfaces.iface);
hostapd_global_deinit(pid_file);
@ -650,6 +754,9 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_close_file();
wpa_debug_close_linux_tracing();
os_free(bss_config);
os_program_deinit();

342
contrib/wpa/hostapd/wps-ap-nfc.py Executable file
View File

@ -0,0 +1,342 @@
#!/usr/bin/python
#
# Example nfcpy to hostapd wrapper for WPS NFC operations
# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import os
import sys
import time
import argparse
import nfc
import nfc.ndef
import nfc.llcp
import nfc.handover
import logging
import wpaspy
wpas_ctrl = '/var/run/hostapd'
continue_loop = True
summary_file = None
success_file = None
def summary(txt):
print txt
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
def success_report(txt):
summary(txt)
if success_file:
with open(success_file, 'a') as f:
f.write(txt + "\n")
def wpas_connect():
ifaces = []
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
except OSError, error:
print "Could not find hostapd: ", error
return None
if len(ifaces) < 1:
print "No hostapd control interface found"
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
except Exception, e:
pass
return None
def wpas_tag_read(message):
wpas = wpas_connect()
if (wpas == None):
return False
if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
return False
return True
def wpas_get_config_token():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_get_password_token():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("WPS_NFC_TOKEN NDEF")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_get_handover_sel():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_report_handover(req, sel):
wpas = wpas_connect()
if (wpas == None):
return None
return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
str(req).encode("hex") + " " +
str(sel).encode("hex"))
class HandoverServer(nfc.handover.HandoverServer):
def __init__(self, llc):
super(HandoverServer, self).__init__(llc)
self.ho_server_processing = False
self.success = False
# override to avoid parser error in request/response.pretty() in nfcpy
# due to new WSC handover format
def _process_request(self, request):
summary("received handover request {}".format(request.type))
response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
if not request.type == 'urn:nfc:wkt:Hr':
summary("not a handover request")
else:
try:
request = nfc.ndef.HandoverRequestMessage(request)
except nfc.ndef.DecodeError as e:
summary("error decoding 'Hr' message: {}".format(e))
else:
response = self.process_request(request)
summary("send handover response {}".format(response.type))
return response
def process_request(self, request):
summary("HandoverServer - request received")
try:
print "Parsed handover request: " + request.pretty()
except Exception, e:
print e
print str(request).encode("hex")
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
print "Remote carrier type: " + carrier.type
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel()
if data is None:
summary("Could not get handover select carrier record from hostapd")
continue
print "Handover select carrier record from hostapd:"
print data.encode("hex")
if "OK" in wpas_report_handover(carrier.record, data):
success_report("Handover reported successfully")
else:
summary("Handover report rejected")
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
print "Handover select:"
try:
print sel.pretty()
except Exception, e:
print e
print str(sel).encode("hex")
summary("Sending handover select")
self.success = True
return sel
def wps_tag_read(tag):
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
print "record type " + record.type
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to hostapd")
success = wpas_tag_read(tag.ndef.message)
break
else:
summary("Empty tag")
if success:
success_report("Tag read succeeded")
return success
def rdwr_connected_write(tag):
summary("Tag found - writing - " + str(tag))
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
print "Done - remove tag"
global only_one
if only_one:
global continue_loop
continue_loop = False
global write_wait_remove
while write_wait_remove and tag.is_present:
time.sleep(0.1)
def wps_write_config_tag(clf, wait_remove=True):
summary("Write WPS config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_config_token()
if write_data == None:
summary("Could not get WPS config token from hostapd")
return
print "Touch an NFC tag"
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_password_tag(clf, wait_remove=True):
summary("Write WPS password token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_password_token()
if write_data == None:
summary("Could not get WPS password token from hostapd")
return
print "Touch an NFC tag"
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def rdwr_connected(tag):
global only_one, no_wait
summary("Tag connected: " + str(tag))
if tag.ndef:
print "NDEF tag: " + tag.type
try:
print tag.ndef.message.pretty()
except Exception, e:
print e
success = wps_tag_read(tag)
if only_one and success:
global continue_loop
continue_loop = False
else:
summary("Not an NDEF tag - remove tag")
return True
return not no_wait
def llcp_startup(clf, llc):
print "Start LLCP server"
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
print "P2P LLCP connected"
global wait_connection
wait_connection = False
global srv
srv.start()
return True
def main():
clf = nfc.ContactlessFrontend()
parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
action='store_const', dest='loglevel',
help='verbose debug output')
parser.add_argument('-q', const=logging.WARNING, action='store_const',
dest='loglevel', help='be quiet')
parser.add_argument('--only-one', '-1', action='store_true',
help='run only one operation and exit')
parser.add_argument('--no-wait', action='store_true',
help='do not wait for tag to be removed before exiting')
parser.add_argument('--summary',
help='summary file for writing status updates')
parser.add_argument('--success',
help='success file for writing success update')
parser.add_argument('command', choices=['write-config',
'write-password'],
nargs='?')
args = parser.parse_args()
global only_one
only_one = args.only_one
global no_wait
no_wait = args.no_wait
if args.summary:
global summary_file
summary_file = args.summary
if args.success:
global success_file
success_file = args.success
logging.basicConfig(level=args.loglevel)
try:
if not clf.open("usb"):
print "Could not open connection with an NFC device"
raise SystemExit
if args.command == "write-config":
wps_write_config_tag(clf, wait_remove=not args.no_wait)
raise SystemExit
if args.command == "write-password":
wps_write_password_tag(clf, wait_remove=not args.no_wait)
raise SystemExit
global continue_loop
while continue_loop:
print "Waiting for a tag or peer to be touched"
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
llcp={'on-startup': llcp_startup,
'on-connect': llcp_connected}):
break
except Exception, e:
print "clf.connect failed"
global srv
if only_one and srv and srv.success:
raise SystemExit
except KeyboardInterrupt:
raise SystemExit
finally:
clf.close()
raise SystemExit
if __name__ == '__main__':
main()

View File

@ -0,0 +1,81 @@
LOCAL_PATH := $(call my-dir)
INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/../../src/utils
INCLUDES += $(LOCAL_PATH)/../../src/common
INCLUDES += $(LOCAL_PATH)/../../src
INCLUDES += external/openssl/include
INCLUDES += external/libxml2/include
INCLUDES += external/curl/include
INCLUDES += external/webkit/Source/WebKit/gtk
# 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
L_CFLAGS += -DCONFIG_CTRL_IFACE
L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
OBJS = spp_client.c
OBJS += oma_dm_client.c
OBJS += osu_client.c
OBJS += est.c
OBJS += ../../src/common/wpa_ctrl.c
OBJS += ../../src/common/wpa_helpers.c
OBJS += ../../src/utils/xml-utils.c
#OBJS += ../../src/utils/browser-android.c
OBJS += ../../src/utils/browser-wpadebug.c
OBJS += ../../src/utils/wpabuf.c
OBJS += ../../src/utils/eloop.c
OBJS += ../../src/wps/httpread.c
OBJS += ../../src/wps/http_server.c
OBJS += ../../src/utils/xml_libxml2.c
OBJS += ../../src/utils/http_curl.c
OBJS += ../../src/utils/base64.c
OBJS += ../../src/utils/os_unix.c
L_CFLAGS += -DCONFIG_DEBUG_FILE
OBJS += ../../src/utils/wpa_debug.c
OBJS += ../../src/utils/common.c
OBJS += ../../src/crypto/crypto_internal.c
OBJS += ../../src/crypto/md5-internal.c
OBJS += ../../src/crypto/sha1-internal.c
OBJS += ../../src/crypto/sha256-internal.c
L_CFLAGS += -DEAP_TLS_OPENSSL
L_CFLAGS += -Wno-unused-parameter
########################
include $(CLEAR_VARS)
LOCAL_MODULE := hs20-osu-client
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libc libcutils
LOCAL_SHARED_LIBRARIES += libcrypto libssl
#LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_STATIC_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += libicuuc
LOCAL_SHARED_LIBRARIES += libcurl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS)
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)
########################

View File

@ -0,0 +1,94 @@
all: hs20-osu-client
ifndef CC
CC=gcc
endif
ifndef LDO
LDO=$(CC)
endif
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common
CFLAGS += -I../../src
ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS)
endif
endif
OBJS=spp_client.o
OBJS += oma_dm_client.o
OBJS += osu_client.o
OBJS += est.o
OBJS += ../../src/utils/xml-utils.o
CFLAGS += -DCONFIG_CTRL_IFACE
CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
OBJS += ../../src/common/wpa_ctrl.o ../../src/common/wpa_helpers.o
ifdef CONFIG_NO_BROWSER
CFLAGS += -DCONFIG_NO_BROWSER
else
ifdef CONFIG_BROWSER_SYSTEM
OBJS += ../../src/utils/eloop.o
OBJS += ../../src/utils/wpabuf.o
OBJS += ../../src/wps/httpread.o
OBJS += ../../src/wps/http_server.o
OBJS += ../../src/utils/browser-system.o
else
OBJS += ../../src/utils/browser.o
endif
endif
OBJS += ../../src/utils/xml_libxml2.o
OBJS += ../../src/utils/http_curl.o
OBJS += ../../src/utils/base64.o
OBJS += ../../src/utils/os_unix.o
CFLAGS += -DCONFIG_DEBUG_FILE
OBJS += ../../src/utils/wpa_debug.o
OBJS += ../../src/utils/common.o
OBJS += ../../src/crypto/crypto_internal.o
OBJS += ../../src/crypto/md5-internal.o
OBJS += ../../src/crypto/sha1-internal.o
OBJS += ../../src/crypto/sha256-internal.o
CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
LIBS += -lcurl
CFLAGS += -DEAP_TLS_OPENSSL
LIBS += -lssl -lcrypto
hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
clean:
rm -f core *~ *.o *.d hs20-osu-client
rm -f ../../src/utils/*.o
rm -f ../../src/utils/*.d
rm -f ../../src/common/*.o
rm -f ../../src/common/*.d
rm -f ../../src/crypto/*.o
rm -f ../../src/crypto/*.d
rm -f ../../src/wps/*.o
rm -f ../../src/wps/*.d
-include $(OBJS:%.o=%.d)

View File

@ -0,0 +1,47 @@
<DevDetail xmlns="urn:oma:mo:oma-dm-devdetail:1.0">
<Ext>
<org.wi-fi>
<Wi-Fi>
<EAPMethodList>
<EAPMethod1>
<EAPType>13</EAPType>
</EAPMethod1>
<EAPMethod2>
<EAPType>21</EAPType>
<InnerMethod>MS-CHAP-V2</InnerMethod>
</EAPMethod2>
<EAPMethod3>
<EAPType>18</EAPType>
</EAPMethod3>
<EAPMethod4>
<EAPType>23</EAPType>
</EAPMethod4>
<EAPMethod5>
<EAPType>50</EAPType>
</EAPMethod5>
</EAPMethodList>
<ManufacturingCertificate>false</ManufacturingCertificate>
<Wi-FiMACAddress>020102030405</Wi-FiMACAddress>
<IMSI>310026000000000</IMSI>
<IMEI_MEID>imei:490123456789012</IMEI_MEID>
<ClientTriggerRedirectURI>http://localhost:12345/</ClientTriggerRedirectURI>
<Ops>
<launchBrowserToURI></launchBrowserToURI>
<negotiateClientCertTLS></negotiateClientCertTLS>
<getCertificate></getCertificate>
</Ops>
</Wi-Fi>
</org.wi-fi>
</Ext>
<URI>
<MaxDepth>0</MaxDepth>
<MaxTotLen>0</MaxTotLen>
<MaxSegLen>0</MaxSegLen>
</URI>
<DevType>MobilePhone</DevType>
<OEM>Manufacturer</OEM>
<FwV>1.0</FwV>
<SwV>1.0</SwV>
<HwV>1.0</HwV>
<LrgObj>false</LrgObj>
</DevDetail>

View File

@ -0,0 +1,7 @@
<DevInfo xmlns="urn:oma:mo:oma-dm-devinfo:1.0">
<DevId>urn:Example:HS20-station:123456</DevId>
<Man>Manufacturer</Man>
<Mod>HS20-station</Mod>
<DmV>1.2</DmV>
<Lang>en</Lang>
</DevInfo>

View File

@ -0,0 +1,715 @@
/*
* Hotspot 2.0 OSU client - EST client
* Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "common.h"
#include "utils/base64.h"
#include "utils/xml-utils.h"
#include "utils/http-utils.h"
#include "osu_client.h"
static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
size_t len, char *pem_file, char *der_file)
{
PKCS7 *p7 = NULL;
const unsigned char *p = pkcs7;
STACK_OF(X509) *certs;
int i, num, ret = -1;
BIO *out = NULL;
p7 = d2i_PKCS7(NULL, &p, len);
if (p7 == NULL) {
wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
ERR_error_string(ERR_get_error(), NULL));
write_result(ctx, "Could not parse PKCS#7 object from EST");
goto fail;
}
switch (OBJ_obj2nid(p7->type)) {
case NID_pkcs7_signed:
certs = p7->d.sign->cert;
break;
case NID_pkcs7_signedAndEnveloped:
certs = p7->d.signed_and_enveloped->cert;
break;
default:
certs = NULL;
break;
}
if (!certs || ((num = sk_X509_num(certs)) == 0)) {
wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
write_result(ctx, "No certificates found in PKCS#7 object");
goto fail;
}
if (der_file) {
FILE *f = fopen(der_file, "wb");
if (f == NULL)
goto fail;
i2d_X509_fp(f, sk_X509_value(certs, 0));
fclose(f);
}
if (pem_file) {
out = BIO_new(BIO_s_file());
if (out == NULL ||
BIO_write_filename(out, pem_file) <= 0)
goto fail;
for (i = 0; i < num; i++) {
X509 *cert = sk_X509_value(certs, i);
X509_print(out, cert);
PEM_write_bio_X509(out, cert);
BIO_puts(out, "\n");
}
}
ret = 0;
fail:
PKCS7_free(p7);
if (out)
BIO_free_all(out);
return ret;
}
int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
{
char *buf, *resp;
size_t buflen;
unsigned char *pkcs7;
size_t pkcs7_len, resp_len;
int res;
buflen = os_strlen(url) + 100;
buf = os_malloc(buflen);
if (buf == NULL)
return -1;
os_snprintf(buf, buflen, "%s/cacerts", url);
wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf);
write_summary(ctx, "Download EST cacerts from %s", buf);
ctx->no_osu_cert_validation = 1;
http_ocsp_set(ctx->http, 1);
res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
ctx->ca_fname);
http_ocsp_set(ctx->http,
(ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
ctx->no_osu_cert_validation = 0;
if (res < 0) {
wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s",
buf);
write_result(ctx, "Failed to download EST cacerts from %s",
buf);
os_free(buf);
return -1;
}
os_free(buf);
resp = os_readfile("Cert/est-cacerts.txt", &resp_len);
if (resp == NULL) {
wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt");
write_result(ctx, "Could not read EST cacerts");
return -1;
}
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
if (pkcs7 && pkcs7_len < resp_len / 2) {
wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
(unsigned int) pkcs7_len, (unsigned int) resp_len);
os_free(pkcs7);
pkcs7 = NULL;
}
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
pkcs7 = os_malloc(resp_len);
if (pkcs7) {
os_memcpy(pkcs7, resp, resp_len);
pkcs7_len = resp_len;
}
}
os_free(resp);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts");
write_result(ctx, "Could not fetch EST PKCS#7 cacerts");
return -1;
}
res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem",
NULL);
os_free(pkcs7);
if (res < 0) {
wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response");
write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response");
return -1;
}
unlink("Cert/est-cacerts.txt");
return 0;
}
/*
* CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
*
* AttrOrOID ::= CHOICE {
* oid OBJECT IDENTIFIER,
* attribute Attribute }
*
* Attribute ::= SEQUENCE {
* type OBJECT IDENTIFIER,
* values SET SIZE(1..MAX) OF OBJECT IDENTIFIER }
*/
typedef struct {
ASN1_OBJECT *type;
STACK_OF(ASN1_OBJECT) *values;
} Attribute;
typedef struct {
int type;
union {
ASN1_OBJECT *oid;
Attribute *attribute;
} d;
} AttrOrOID;
typedef struct {
int type;
STACK_OF(AttrOrOID) *attrs;
} CsrAttrs;
ASN1_SEQUENCE(Attribute) = {
ASN1_SIMPLE(Attribute, type, ASN1_OBJECT),
ASN1_SET_OF(Attribute, values, ASN1_OBJECT)
} ASN1_SEQUENCE_END(Attribute);
ASN1_CHOICE(AttrOrOID) = {
ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT),
ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute)
} ASN1_CHOICE_END(AttrOrOID);
ASN1_CHOICE(CsrAttrs) = {
ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID)
} ASN1_CHOICE_END(CsrAttrs);
IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs);
static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid,
STACK_OF(X509_EXTENSION) *exts)
{
char txt[100];
int res;
if (!oid)
return;
res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
if (res < 0 || res >= (int) sizeof(txt))
return;
if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) {
wpa_printf(MSG_INFO, "TODO: csrattr challengePassword");
} else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) {
wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption");
} else {
wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt);
}
}
static void add_csrattrs_ext_req(struct hs20_osu_client *ctx,
STACK_OF(ASN1_OBJECT) *values,
STACK_OF(X509_EXTENSION) *exts)
{
char txt[100];
int i, num, res;
num = sk_ASN1_OBJECT_num(values);
for (i = 0; i < num; i++) {
ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i);
res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
if (res < 0 || res >= (int) sizeof(txt))
continue;
if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) {
wpa_printf(MSG_INFO, "TODO: extReq macAddress");
} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) {
wpa_printf(MSG_INFO, "TODO: extReq imei");
} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) {
wpa_printf(MSG_INFO, "TODO: extReq meid");
} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) {
wpa_printf(MSG_INFO, "TODO: extReq DevId");
} else {
wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s",
txt);
}
}
}
static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr,
STACK_OF(X509_EXTENSION) *exts)
{
char txt[100], txt2[100];
int i, num, res;
if (!attr || !attr->type || !attr->values)
return;
res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1);
if (res < 0 || res >= (int) sizeof(txt))
return;
if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) {
add_csrattrs_ext_req(ctx, attr->values, exts);
return;
}
num = sk_ASN1_OBJECT_num(attr->values);
for (i = 0; i < num; i++) {
ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i);
res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1);
if (res < 0 || res >= (int) sizeof(txt2))
continue;
wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s",
txt, txt2);
}
}
static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
STACK_OF(X509_EXTENSION) *exts)
{
int i, num;
if (!csrattrs || ! csrattrs->attrs)
return;
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
for (i = 0; i < num; i++) {
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
switch (ao->type) {
case 0:
add_csrattrs_oid(ctx, ao->d.oid, exts);
break;
case 1:
add_csrattrs_attr(ctx, ao->d.attribute, exts);
break;
}
}
}
static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
char *csr_pem, char *est_req, char *old_cert,
CsrAttrs *csrattrs)
{
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa;
X509_REQ *req = NULL;
int ret = -1;
unsigned int val;
X509_NAME *subj = NULL;
char name[100];
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ex;
BIO *out;
wpa_printf(MSG_INFO, "Generate RSA private key");
write_summary(ctx, "Generate RSA private key");
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!pctx)
return -1;
if (EVP_PKEY_keygen_init(pctx) <= 0)
goto fail;
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0)
goto fail;
if (EVP_PKEY_keygen(pctx, &pkey) <= 0)
goto fail;
EVP_PKEY_CTX_free(pctx);
pctx = NULL;
rsa = EVP_PKEY_get1_RSA(pkey);
if (rsa == NULL)
goto fail;
if (key_pem) {
FILE *f = fopen(key_pem, "wb");
if (f == NULL)
goto fail;
if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL,
NULL)) {
wpa_printf(MSG_INFO, "Could not write private key: %s",
ERR_error_string(ERR_get_error(), NULL));
fclose(f);
goto fail;
}
fclose(f);
}
wpa_printf(MSG_INFO, "Generate CSR");
write_summary(ctx, "Generate CSR");
req = X509_REQ_new();
if (req == NULL)
goto fail;
if (old_cert) {
FILE *f;
X509 *cert;
int res;
f = fopen(old_cert, "r");
if (f == NULL)
goto fail;
cert = PEM_read_X509(f, NULL, NULL, NULL);
fclose(f);
if (cert == NULL)
goto fail;
res = X509_REQ_set_subject_name(req,
X509_get_subject_name(cert));
X509_free(cert);
if (!res)
goto fail;
} else {
os_get_random((u8 *) &val, sizeof(val));
os_snprintf(name, sizeof(name), "cert-user-%u", val);
subj = X509_NAME_new();
if (subj == NULL ||
!X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC,
(unsigned char *) name,
-1, -1, 0) ||
!X509_REQ_set_subject_name(req, subj))
goto fail;
X509_NAME_free(subj);
subj = NULL;
}
if (!X509_REQ_set_pubkey(req, pkey))
goto fail;
exts = sk_X509_EXTENSION_new_null();
if (!exts)
goto fail;
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
"CA:FALSE");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
"nonRepudiation,digitalSignature,keyEncipherment");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage,
"1.3.6.1.4.1.40808.1.1.2");
if (ex == NULL ||
!sk_X509_EXTENSION_push(exts, ex))
goto fail;
add_csrattrs(ctx, csrattrs, exts);
if (!X509_REQ_add_extensions(req, exts))
goto fail;
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
exts = NULL;
if (!X509_REQ_sign(req, pkey, EVP_sha256()))
goto fail;
out = BIO_new(BIO_s_mem());
if (out) {
char *txt;
size_t rlen;
X509_REQ_print(out, req);
rlen = BIO_ctrl_pending(out);
txt = os_malloc(rlen + 1);
if (txt) {
int res = BIO_read(out, txt, rlen);
if (res > 0) {
txt[res] = '\0';
wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s",
txt);
}
os_free(txt);
}
BIO_free(out);
}
if (csr_pem) {
FILE *f = fopen(csr_pem, "w");
if (f == NULL)
goto fail;
X509_REQ_print_fp(f, req);
if (!PEM_write_X509_REQ(f, req)) {
fclose(f);
goto fail;
}
fclose(f);
}
if (est_req) {
BIO *mem = BIO_new(BIO_s_mem());
BUF_MEM *ptr;
char *pos, *end, *buf_end;
FILE *f;
if (mem == NULL)
goto fail;
if (!PEM_write_bio_X509_REQ(mem, req)) {
BIO_free(mem);
goto fail;
}
BIO_get_mem_ptr(mem, &ptr);
pos = ptr->data;
buf_end = pos + ptr->length;
/* Remove START/END lines */
while (pos < buf_end && *pos != '\n')
pos++;
if (pos == buf_end) {
BIO_free(mem);
goto fail;
}
pos++;
end = pos;
while (end < buf_end && *end != '-')
end++;
f = fopen(est_req, "w");
if (f == NULL) {
BIO_free(mem);
goto fail;
}
fwrite(pos, end - pos, 1, f);
fclose(f);
BIO_free(mem);
}
ret = 0;
fail:
if (exts)
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
if (subj)
X509_NAME_free(subj);
if (req)
X509_REQ_free(req);
if (pkey)
EVP_PKEY_free(pkey);
if (pctx)
EVP_PKEY_CTX_free(pctx);
return ret;
}
int est_build_csr(struct hs20_osu_client *ctx, const char *url)
{
char *buf;
size_t buflen;
int res;
char old_cert_buf[200];
char *old_cert = NULL;
CsrAttrs *csrattrs = NULL;
buflen = os_strlen(url) + 100;
buf = os_malloc(buflen);
if (buf == NULL)
return -1;
os_snprintf(buf, buflen, "%s/csrattrs", url);
wpa_printf(MSG_INFO, "Download csrattrs from %s", buf);
write_summary(ctx, "Download EST csrattrs from %s", buf);
ctx->no_osu_cert_validation = 1;
http_ocsp_set(ctx->http, 1);
res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
ctx->ca_fname);
http_ocsp_set(ctx->http,
(ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
ctx->no_osu_cert_validation = 0;
os_free(buf);
if (res < 0) {
wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed");
} else {
size_t resp_len;
char *resp;
unsigned char *attrs;
const unsigned char *pos;
size_t attrs_len;
resp = os_readfile("Cert/est-csrattrs.txt", &resp_len);
if (resp == NULL) {
wpa_printf(MSG_INFO, "Could not read csrattrs");
return -1;
}
attrs = base64_decode((unsigned char *) resp, resp_len,
&attrs_len);
os_free(resp);
if (attrs == NULL) {
wpa_printf(MSG_INFO, "Could not base64 decode csrattrs");
return -1;
}
unlink("Cert/est-csrattrs.txt");
pos = attrs;
csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len);
os_free(attrs);
if (csrattrs == NULL) {
wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1");
/* Continue assuming no additional requirements */
}
}
if (ctx->client_cert_present) {
os_snprintf(old_cert_buf, sizeof(old_cert_buf),
"SP/%s/client-cert.pem", ctx->fqdn);
old_cert = old_cert_buf;
}
res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem",
"Cert/est-req.b64", old_cert, csrattrs);
if (csrattrs)
CsrAttrs_free(csrattrs);
return res;
}
int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
const char *user, const char *pw)
{
char *buf, *resp, *req, *req2;
size_t buflen, resp_len, len, pkcs7_len;
unsigned char *pkcs7;
FILE *f;
char client_cert_buf[200];
char client_key_buf[200];
const char *client_cert = NULL, *client_key = NULL;
int res;
req = os_readfile("Cert/est-req.b64", &len);
if (req == NULL) {
wpa_printf(MSG_INFO, "Could not read Cert/req.b64");
return -1;
}
req2 = os_realloc(req, len + 1);
if (req2 == NULL) {
os_free(req);
return -1;
}
req2[len] = '\0';
req = req2;
wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req);
buflen = os_strlen(url) + 100;
buf = os_malloc(buflen);
if (buf == NULL) {
os_free(req);
return -1;
}
if (ctx->client_cert_present) {
os_snprintf(buf, buflen, "%s/simplereenroll", url);
os_snprintf(client_cert_buf, sizeof(client_cert_buf),
"SP/%s/client-cert.pem", ctx->fqdn);
client_cert = client_cert_buf;
os_snprintf(client_key_buf, sizeof(client_key_buf),
"SP/%s/client-key.pem", ctx->fqdn);
client_key = client_key_buf;
} else
os_snprintf(buf, buflen, "%s/simpleenroll", url);
wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf);
write_summary(ctx, "EST simpleenroll URL: %s", buf);
ctx->no_osu_cert_validation = 1;
http_ocsp_set(ctx->http, 1);
resp = http_post(ctx->http, buf, req, "application/pkcs10",
"Content-Transfer-Encoding: base64",
ctx->ca_fname, user, pw, client_cert, client_key,
&resp_len);
http_ocsp_set(ctx->http,
(ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
ctx->no_osu_cert_validation = 0;
os_free(buf);
if (resp == NULL) {
wpa_printf(MSG_INFO, "EST certificate enrollment failed");
write_result(ctx, "EST certificate enrollment failed");
return -1;
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
f = fopen("Cert/est-resp.raw", "w");
if (f) {
fwrite(resp, resp_len, 1, f);
fclose(f);
}
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
pkcs7 = os_malloc(resp_len);
if (pkcs7) {
os_memcpy(pkcs7, resp, resp_len);
pkcs7_len = resp_len;
}
}
os_free(resp);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response");
write_result(ctx, "Failed to parse EST simpleenroll base64 response");
return -1;
}
res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem",
"Cert/est_cert.der");
os_free(pkcs7);
if (res < 0) {
wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file");
write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file");
return -1;
}
wpa_printf(MSG_INFO, "EST simple%senroll completed successfully",
ctx->client_cert_present ? "re" : "");
write_summary(ctx, "EST simple%senroll completed successfully",
ctx->client_cert_present ? "re" : "");
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/*
* Hotspot 2.0 - OSU client
* Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef OSU_CLIENT_H
#define OSU_CLIENT_H
#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
#define URN_HS20_DEVDETAIL_EXT "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0"
#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
#define MAX_OSU_VALS 10
struct osu_lang_text {
char lang[4];
char text[253];
};
struct hs20_osu_client {
struct xml_node_ctx *xml;
struct http_ctx *http;
int no_reconnect;
char pps_fname[300];
char *devid;
const char *result_file;
const char *summary_file;
const char *ifname;
const char *ca_fname;
int no_osu_cert_validation; /* for EST operations */
char *fqdn;
char *server_url;
struct osu_lang_text friendly_name[MAX_OSU_VALS];
size_t friendly_name_count;
size_t icon_count;
char icon_filename[MAX_OSU_VALS][256];
u8 icon_hash[MAX_OSU_VALS][32];
int pps_cred_set;
int pps_updated;
int client_cert_present;
char **server_dnsname;
size_t server_dnsname_count;
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
};
/* osu_client.c */
void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
xml_node_t *node);
int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert);
int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
xml_node_t *add_mo, char *fname, size_t fname_len);
void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
const char *alt_loc, char **user, char **pw);
int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
xml_node_t *pps);
void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname);
/* spp_client.c */
void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps);
void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps);
int cmd_prov(struct hs20_osu_client *ctx, const char *url);
int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url);
/* oma_dm_client.c */
int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url);
int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url);
void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps);
void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps);
void cmd_oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname);
void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
const char *add_fname);
void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
const char *replace_fname);
/* est.c */
int est_load_cacerts(struct hs20_osu_client *ctx, const char *url);
int est_build_csr(struct hs20_osu_client *ctx, const char *url);
int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
const char *user, const char *pw);
#endif /* OSU_CLIENT_H */

View File

@ -0,0 +1,995 @@
/*
* Hotspot 2.0 SPP client
* Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <sys/stat.h>
#include "common.h"
#include "browser.h"
#include "wpa_ctrl.h"
#include "wpa_helpers.h"
#include "xml-utils.h"
#include "http-utils.h"
#include "utils/base64.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
#include "osu_client.h"
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
const char *error_code);
static void hs20_policy_update_complete(
struct hs20_osu_client *ctx, const char *pps_fname);
static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
char *attr_name)
{
return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
}
static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
const char *expected_name)
{
struct xml_node_ctx *xctx = ctx->xml;
const char *name;
char *err;
int ret;
if (!xml_node_is_element(xctx, node))
return -1;
name = xml_node_get_localname(xctx, node);
if (name == NULL)
return -1;
if (strcmp(expected_name, name) != 0) {
wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
name, expected_name);
write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
name, expected_name);
return -1;
}
ret = xml_validate(xctx, node, "spp.xsd", &err);
if (ret < 0) {
wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
write_summary(ctx, "SPP XML schema validation failed");
os_free(err);
}
return ret;
}
static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
xml_node_t *parent, const char *urn,
const char *fname)
{
xml_node_t *node;
xml_node_t *fnode, *tnds;
char *str;
fnode = node_from_file(ctx, fname);
if (!fnode)
return;
tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
xml_node_free(ctx, fnode);
if (!tnds)
return;
str = xml_node_to_str(ctx, tnds);
xml_node_free(ctx, tnds);
if (str == NULL)
return;
node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
if (node)
xml_node_add_attr(ctx, node, ns, "moURN", urn);
os_free(str);
}
static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
xml_namespace_t **ret_ns,
const char *session_id,
const char *reason)
{
xml_namespace_t *ns;
xml_node_t *spp_node;
write_summary(ctx, "Building sppPostDevData requestReason='%s'",
reason);
spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
"sppPostDevData");
if (spp_node == NULL)
return NULL;
if (ret_ns)
*ret_ns = ns;
xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
if (session_id)
xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
session_id);
xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
"http://localhost:12345/");
xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
"1.0");
xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
"devinfo.xml");
add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
"devdetail.xml");
return spp_node;
}
static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
xml_node_t *update)
{
xml_node_t *node, *parent, *tnds, *unode;
char *str;
const char *name;
char *uri, *pos;
char *cdata, *cdata_end;
size_t fqdn_len;
wpa_printf(MSG_INFO, "Processing updateNode");
debug_dump_node(ctx, "updateNode", update);
uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
if (uri == NULL) {
wpa_printf(MSG_INFO, "No managementTreeURI present");
return -1;
}
wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
name = os_strrchr(uri, '/');
if (name == NULL) {
wpa_printf(MSG_INFO, "Unexpected URI");
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
name++;
wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
str = xml_node_get_text(ctx->xml, update);
if (str == NULL) {
wpa_printf(MSG_INFO, "Could not extract MO text");
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
cdata = strstr(str, "<![CDATA[");
cdata_end = strstr(str, "]]>");
if (cdata && cdata_end && cdata_end > cdata &&
cdata < strstr(str, "MgmtTree") &&
cdata_end > strstr(str, "/MgmtTree")) {
char *tmp;
wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
tmp = strdup(cdata + 9);
if (tmp) {
cdata_end = strstr(tmp, "]]>");
if (cdata_end)
*cdata_end = '\0';
wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
tmp);
tnds = xml_node_from_buf(ctx->xml, tmp);
free(tmp);
} else
tnds = NULL;
} else
tnds = xml_node_from_buf(ctx->xml, str);
xml_node_get_text_free(ctx->xml, str);
if (tnds == NULL) {
wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
unode = tnds_to_mo(ctx->xml, tnds);
xml_node_free(ctx->xml, tnds);
if (unode == NULL) {
wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
debug_dump_node(ctx, "Parsed TNDS", unode);
if (get_node_uri(ctx->xml, unode, name) == NULL) {
wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
pos = uri + 8;
if (ctx->fqdn == NULL) {
wpa_printf(MSG_INFO, "FQDN not known");
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
fqdn_len = os_strlen(ctx->fqdn);
if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
pos[fqdn_len] != '/') {
wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
ctx->fqdn);
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
pos += fqdn_len + 1;
if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
ctx->fqdn);
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
pos += 24;
wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
node = get_node(ctx->xml, pps, pos);
if (node) {
parent = xml_node_get_parent(ctx->xml, node);
xml_node_detach(ctx->xml, node);
wpa_printf(MSG_INFO, "Replace '%s' node", name);
} else {
char *pos2;
pos2 = os_strrchr(pos, '/');
if (pos2 == NULL) {
parent = pps;
} else {
*pos2 = '\0';
parent = get_node(ctx->xml, pps, pos);
}
if (parent == NULL) {
wpa_printf(MSG_INFO, "Could not find parent %s", pos);
xml_node_free(ctx->xml, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return -1;
}
wpa_printf(MSG_INFO, "Add '%s' node", name);
}
xml_node_add_child(ctx->xml, parent, unode);
xml_node_get_attr_value_free(ctx->xml, uri);
return 0;
}
static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
const char *pps_fname, xml_node_t *pps)
{
wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
xml_node_for_each_sibling(ctx->xml, update) {
xml_node_for_each_check(ctx->xml, update);
if (process_update_node(ctx, pps, update) < 0)
return -1;
}
return update_pps_file(ctx, pps_fname, pps);
}
static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
const char *pps_fname)
{
/*
* Update wpa_supplicant credentials and reconnect using updated
* information.
*/
wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
cmd_set_pps(ctx, pps_fname);
if (ctx->no_reconnect)
return;
wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
}
static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
xml_node_t *cmd,
const char *session_id,
const char *pps_fname)
{
xml_namespace_t *ns;
xml_node_t *node, *ret_node;
char *urn;
urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
if (!urn) {
wpa_printf(MSG_INFO, "No URN included");
return NULL;
}
wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
if (strcasecmp(urn, URN_HS20_PPS) != 0) {
wpa_printf(MSG_INFO, "Unsupported moURN");
xml_node_get_attr_value_free(ctx->xml, urn);
return NULL;
}
xml_node_get_attr_value_free(ctx->xml, urn);
if (!pps_fname) {
wpa_printf(MSG_INFO, "PPS file name no known");
return NULL;
}
node = build_spp_post_dev_data(ctx, &ns, session_id,
"MO upload");
if (node == NULL)
return NULL;
add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
ret_node = soap_send_receive(ctx->http, node);
if (ret_node == NULL)
return NULL;
debug_dump_node(ctx, "Received response to MO upload", ret_node);
if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
wpa_printf(MSG_INFO, "SPP validation failed");
xml_node_free(ctx->xml, ret_node);
return NULL;
}
return ret_node;
}
static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
char *fname, size_t fname_len)
{
char *uri, *urn;
int ret;
debug_dump_node(ctx, "Received addMO", add_mo);
urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
if (urn == NULL) {
wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
return -1;
}
wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
if (strcasecmp(urn, URN_HS20_PPS) != 0) {
wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
xml_node_get_attr_value_free(ctx->xml, urn);
return -1;
}
xml_node_get_attr_value_free(ctx->xml, urn);
uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
if (uri == NULL) {
wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
return -1;
}
wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
xml_node_get_attr_value_free(ctx->xml, uri);
return ret;
}
static int process_spp_user_input_response(struct hs20_osu_client *ctx,
const char *session_id,
xml_node_t *add_mo)
{
int ret;
char fname[300];
debug_dump_node(ctx, "addMO", add_mo);
wpa_printf(MSG_INFO, "Subscription registration completed");
if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
wpa_printf(MSG_INFO, "Could not add MO");
ret = hs20_spp_update_response(
ctx, session_id,
"Error occurred",
"MO addition or update failed");
return 0;
}
ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
if (ret == 0)
hs20_sub_rem_complete(ctx, fname);
return 0;
}
static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
const char *session_id)
{
xml_node_t *node, *ret_node;
node = build_spp_post_dev_data(ctx, NULL, session_id,
"User input completed");
if (node == NULL)
return NULL;
ret_node = soap_send_receive(ctx->http, node);
if (!ret_node) {
if (soap_reinit_client(ctx->http) < 0)
return NULL;
wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
node = build_spp_post_dev_data(ctx, NULL, session_id,
"User input completed");
if (node == NULL)
return NULL;
ret_node = soap_send_receive(ctx->http, node);
if (ret_node == NULL)
return NULL;
wpa_printf(MSG_INFO, "Continue with new connection");
}
if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
wpa_printf(MSG_INFO, "SPP validation failed");
xml_node_free(ctx->xml, ret_node);
return NULL;
}
return ret_node;
}
static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
xml_node_t *cmd,
const char *session_id,
const char *pps_fname)
{
xml_namespace_t *ns;
xml_node_t *node, *ret_node;
int res;
wpa_printf(MSG_INFO, "Client certificate enrollment");
res = osu_get_certificate(ctx, cmd);
if (res < 0)
wpa_printf(MSG_INFO, "EST simpleEnroll failed");
node = build_spp_post_dev_data(ctx, &ns, session_id,
res == 0 ?
"Certificate enrollment completed" :
"Certificate enrollment failed");
if (node == NULL)
return NULL;
ret_node = soap_send_receive(ctx->http, node);
if (ret_node == NULL)
return NULL;
debug_dump_node(ctx, "Received response to certificate enrollment "
"completed", ret_node);
if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
wpa_printf(MSG_INFO, "SPP validation failed");
xml_node_free(ctx->xml, ret_node);
return NULL;
}
return ret_node;
}
static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
const char *session_id, const char *pps_fname,
xml_node_t *pps, xml_node_t **ret_node)
{
xml_node_t *cmd;
const char *name;
char *uri;
char *id = strdup(session_id);
if (id == NULL)
return -1;
*ret_node = NULL;
debug_dump_node(ctx, "exec", exec);
xml_node_for_each_child(ctx->xml, cmd, exec) {
xml_node_for_each_check(ctx->xml, cmd);
break;
}
if (!cmd) {
wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
cmd);
free(id);
return -1;
}
name = xml_node_get_localname(ctx->xml, cmd);
if (strcasecmp(name, "launchBrowserToURI") == 0) {
int res;
uri = xml_node_get_text(ctx->xml, cmd);
if (!uri) {
wpa_printf(MSG_INFO, "No URI found");
free(id);
return -1;
}
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "Launch browser to URI '%s'", uri);
res = hs20_web_browser(uri);
xml_node_get_text_free(ctx->xml, uri);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
id);
write_summary(ctx, "User response in browser completed successfully");
*ret_node = hs20_spp_user_input_completed(ctx, id);
free(id);
return *ret_node ? 0 : -1;
} else {
wpa_printf(MSG_INFO, "Failed to receive user response");
write_summary(ctx, "Failed to receive user response");
hs20_spp_update_response(
ctx, id, "Error occurred", "Other");
free(id);
return -1;
}
return 0;
}
if (strcasecmp(name, "uploadMO") == 0) {
if (pps_fname == NULL)
return -1;
*ret_node = hs20_spp_upload_mo(ctx, cmd, id,
pps_fname);
free(id);
return *ret_node ? 0 : -1;
}
if (strcasecmp(name, "getCertificate") == 0) {
*ret_node = hs20_spp_get_certificate(ctx, cmd, id,
pps_fname);
free(id);
return *ret_node ? 0 : -1;
}
wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
free(id);
return -1;
}
enum spp_post_dev_data_use {
SPP_SUBSCRIPTION_REMEDIATION,
SPP_POLICY_UPDATE,
SPP_SUBSCRIPTION_REGISTRATION,
};
static void process_spp_post_dev_data_response(
struct hs20_osu_client *ctx,
enum spp_post_dev_data_use use, xml_node_t *node,
const char *pps_fname, xml_node_t *pps)
{
xml_node_t *child;
char *status = NULL;
xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
char *session_id = NULL;
debug_dump_node(ctx, "sppPostDevDataResponse node", node);
status = get_spp_attr_value(ctx->xml, node, "sppStatus");
if (status == NULL) {
wpa_printf(MSG_INFO, "No sppStatus attribute");
goto out;
}
write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
status);
session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
if (session_id == NULL) {
wpa_printf(MSG_INFO, "No sessionID attribute");
goto out;
}
wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'",
status, session_id);
xml_node_for_each_child(ctx->xml, child, node) {
const char *name;
xml_node_for_each_check(ctx->xml, child);
debug_dump_node(ctx, "child", child);
name = xml_node_get_localname(ctx->xml, child);
wpa_printf(MSG_INFO, "localname: '%s'", name);
if (!update && strcasecmp(name, "updateNode") == 0)
update = child;
if (!exec && strcasecmp(name, "exec") == 0)
exec = child;
if (!add_mo && strcasecmp(name, "addMO") == 0)
add_mo = child;
if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
no_mo = child;
}
if (use == SPP_SUBSCRIPTION_REMEDIATION &&
strcasecmp(status,
"Remediation complete, request sppUpdateResponse") == 0)
{
int res, ret;
if (!update && !no_mo) {
wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
goto out;
}
wpa_printf(MSG_INFO, "Subscription remediation completed");
res = update_pps(ctx, update, pps_fname, pps);
if (res < 0)
wpa_printf(MSG_INFO, "Failed to update PPS MO");
ret = hs20_spp_update_response(
ctx, session_id,
res < 0 ? "Error occurred" : "OK",
res < 0 ? "MO addition or update failed" : NULL);
if (res == 0 && ret == 0)
hs20_sub_rem_complete(ctx, pps_fname);
goto out;
}
if (use == SPP_SUBSCRIPTION_REMEDIATION &&
strcasecmp(status, "Exchange complete, release TLS connection") ==
0) {
if (!no_mo) {
wpa_printf(MSG_INFO, "No noMOUpdate element");
goto out;
}
wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
goto out;
}
if (use == SPP_POLICY_UPDATE &&
strcasecmp(status, "Update complete, request sppUpdateResponse") ==
0) {
int res, ret;
wpa_printf(MSG_INFO, "Policy update received - update PPS");
res = update_pps(ctx, update, pps_fname, pps);
ret = hs20_spp_update_response(
ctx, session_id,
res < 0 ? "Error occurred" : "OK",
res < 0 ? "MO addition or update failed" : NULL);
if (res == 0 && ret == 0)
hs20_policy_update_complete(ctx, pps_fname);
goto out;
}
if (use == SPP_SUBSCRIPTION_REGISTRATION &&
strcasecmp(status, "Provisioning complete, request "
"sppUpdateResponse") == 0) {
if (!add_mo) {
wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
goto out;
}
process_spp_user_input_response(ctx, session_id, add_mo);
node = NULL;
goto out;
}
if (strcasecmp(status, "No update available at this time") == 0) {
wpa_printf(MSG_INFO, "No update available at this time");
goto out;
}
if (strcasecmp(status, "OK") == 0) {
int res;
xml_node_t *ret;
if (!exec) {
wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
goto out;
}
res = hs20_spp_exec(ctx, exec, session_id,
pps_fname, pps, &ret);
/* xml_node_free(ctx->xml, node); */
node = NULL;
if (res == 0 && ret)
process_spp_post_dev_data_response(ctx, use,
ret, pps_fname, pps);
goto out;
}
if (strcasecmp(status, "Error occurred") == 0) {
xml_node_t *err;
char *code = NULL;
err = get_node(ctx->xml, node, "sppError");
if (err)
code = xml_node_get_attr_value(ctx->xml, err,
"errorCode");
wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
code ? code : "N/A");
xml_node_get_attr_value_free(ctx->xml, code);
goto out;
}
wpa_printf(MSG_INFO,
"[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
status);
out:
xml_node_get_attr_value_free(ctx->xml, status);
xml_node_get_attr_value_free(ctx->xml, session_id);
xml_node_free(ctx->xml, node);
}
static int spp_post_dev_data(struct hs20_osu_client *ctx,
enum spp_post_dev_data_use use,
const char *reason,
const char *pps_fname, xml_node_t *pps)
{
xml_node_t *payload;
xml_node_t *ret_node;
payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
if (payload == NULL)
return -1;
ret_node = soap_send_receive(ctx->http, payload);
if (!ret_node) {
const char *err = http_get_err(ctx->http);
if (err) {
wpa_printf(MSG_INFO, "HTTP error: %s", err);
write_result(ctx, "HTTP error: %s", err);
} else {
write_summary(ctx, "Failed to send SOAP message");
}
return -1;
}
if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
wpa_printf(MSG_INFO, "SPP validation failed");
xml_node_free(ctx->xml, ret_node);
return -1;
}
process_spp_post_dev_data_response(ctx, use, ret_node,
pps_fname, pps);
return 0;
}
void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps)
{
wpa_printf(MSG_INFO, "SPP subscription remediation");
write_summary(ctx, "SPP subscription remediation");
os_free(ctx->server_url);
ctx->server_url = os_strdup(address);
if (soap_init_client(ctx->http, address, ctx->ca_fname,
cred_username, cred_password, client_cert,
client_key) == 0) {
spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
"Subscription remediation", pps_fname, pps);
}
}
static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
const char *pps_fname)
{
wpa_printf(MSG_INFO, "Policy update completed");
/*
* Update wpa_supplicant credentials and reconnect using updated
* information.
*/
wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
cmd_set_pps(ctx, pps_fname);
wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
}
static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
xml_node_t *node)
{
char *status, *session_id;
debug_dump_node(ctx, "sppExchangeComplete", node);
status = get_spp_attr_value(ctx->xml, node, "sppStatus");
if (status == NULL) {
wpa_printf(MSG_INFO, "No sppStatus attribute");
return -1;
}
write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
status);
session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
if (session_id == NULL) {
wpa_printf(MSG_INFO, "No sessionID attribute");
xml_node_get_attr_value_free(ctx->xml, status);
return -1;
}
wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'",
status, session_id);
xml_node_get_attr_value_free(ctx->xml, session_id);
if (strcasecmp(status, "Exchange complete, release TLS connection") ==
0) {
xml_node_get_attr_value_free(ctx->xml, status);
return 0;
}
wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
write_summary(ctx, "Unexpected sppStatus '%s'", status);
xml_node_get_attr_value_free(ctx->xml, status);
return -1;
}
static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
const char *error_code)
{
xml_namespace_t *ns;
xml_node_t *spp_node, *node;
spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
"sppUpdateResponse");
if (spp_node == NULL)
return NULL;
xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
if (error_code) {
node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
if (node)
xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
error_code);
}
return spp_node;
}
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
const char *error_code)
{
xml_node_t *node, *ret_node;
int ret;
write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
spp_status, error_code);
node = build_spp_update_response(ctx, session_id, spp_status,
error_code);
if (node == NULL)
return -1;
ret_node = soap_send_receive(ctx->http, node);
if (!ret_node) {
if (soap_reinit_client(ctx->http) < 0)
return -1;
wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
node = build_spp_update_response(ctx, session_id, spp_status,
error_code);
if (node == NULL)
return -1;
ret_node = soap_send_receive(ctx->http, node);
if (ret_node == NULL)
return -1;
wpa_printf(MSG_INFO, "Continue with new connection");
}
if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
wpa_printf(MSG_INFO, "SPP validation failed");
xml_node_free(ctx->xml, ret_node);
return -1;
}
ret = process_spp_exchange_complete(ctx, ret_node);
xml_node_free(ctx->xml, ret_node);
return ret;
}
void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
const char *pps_fname,
const char *client_cert, const char *client_key,
const char *cred_username, const char *cred_password,
xml_node_t *pps)
{
wpa_printf(MSG_INFO, "SPP policy update");
write_summary(ctx, "SPP policy update");
os_free(ctx->server_url);
ctx->server_url = os_strdup(address);
if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
cred_password, client_cert, client_key) == 0) {
spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
pps_fname, pps);
}
}
int cmd_prov(struct hs20_osu_client *ctx, const char *url)
{
unlink("Cert/est_cert.der");
unlink("Cert/est_cert.pem");
if (url == NULL) {
wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
return -1;
}
wpa_printf(MSG_INFO, "Credential provisioning requested");
os_free(ctx->server_url);
ctx->server_url = os_strdup(url);
if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
NULL) < 0)
return -1;
spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
"Subscription registration", NULL, NULL);
return ctx->pps_cred_set ? 0 : -1;
}
int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
{
if (url == NULL) {
wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
return -1;
}
wpa_printf(MSG_INFO, "SIM provisioning requested");
os_free(ctx->server_url);
ctx->server_url = os_strdup(url);
wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
if (wait_ip_addr(ctx->ifname, 15) < 0) {
wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
}
if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
NULL) < 0)
return -1;
spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
"Subscription provisioning", NULL, NULL);
return ctx->pps_cred_set ? 0 : -1;
}

View File

@ -1,429 +0,0 @@
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
--- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
--- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
--- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700
+++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
--- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700
+++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700
@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
}
*(p++)=0; /* Add the NULL method */
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
SSL_COMP *comp;
@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
--- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700
+++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700
@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
--- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
--- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
--- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
--- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
--- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700
+++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700
@@ -131,6 +131,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
--- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
--- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
+++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700
@@ -226,3 +226,6 @@ DTLSv1_server_method
SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
SSL_SESSION_get_id 277 EXIST::FUNCTION:
+SSL_set_hello_extension 278 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
+SSL_set_session_secret_cb 280 EXIST::FUNCTION:

View File

@ -1,429 +0,0 @@
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8d. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h
--- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
+++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
@@ -345,6 +345,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -973,6 +976,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h
--- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
+++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
@@ -296,6 +296,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile
--- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
+++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c
--- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800
+++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800
@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
#endif
*(p++)=0; /* Add the NULL method */
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
#ifndef OPENSSL_NO_COMP
@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c
--- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700
+++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800
@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h
--- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
+++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
@@ -345,6 +345,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -973,6 +976,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c
--- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800
+++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c
--- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800
+++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c
--- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c
--- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700
+++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800
@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h
--- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
+++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
@@ -296,6 +296,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num
--- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
+++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800
@@ -226,3 +226,6 @@ DTLSv1_server_method
SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
SSL_SESSION_get_id 277 EXIST::FUNCTION:
+SSL_set_hello_extension 278 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
+SSL_set_session_secret_cb 280 EXIST::FUNCTION:

View File

@ -1,353 +0,0 @@
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8e. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile
--- openssl-0.9.8e.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
+++ openssl-0.9.8e/ssl/Makefile 2007-03-22 20:23:19.000000000 -0700
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c
--- openssl-0.9.8e.orig/ssl/s3_clnt.c 2006-09-28 05:23:15.000000000 -0700
+++ openssl-0.9.8e/ssl/s3_clnt.c 2007-03-22 20:23:19.000000000 -0700
@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
#endif
*(p++)=0; /* Add the NULL method */
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
#ifndef OPENSSL_NO_COMP
@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c
--- openssl-0.9.8e.orig/ssl/s3_srvr.c 2007-02-07 12:36:40.000000000 -0800
+++ openssl-0.9.8e/ssl/s3_srvr.c 2007-03-22 20:23:19.000000000 -0700
@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h
--- openssl-0.9.8e.orig/ssl/ssl.h 2007-02-19 09:55:07.000000000 -0800
+++ openssl-0.9.8e/ssl/ssl.h 2007-03-22 20:23:19.000000000 -0700
@@ -345,6 +345,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -973,6 +976,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c
--- openssl-0.9.8e.orig/ssl/ssl_err.c 2006-11-21 12:14:46.000000000 -0800
+++ openssl-0.9.8e/ssl/ssl_err.c 2007-03-22 20:23:19.000000000 -0700
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c
--- openssl-0.9.8e.orig/ssl/ssl_sess.c 2007-02-10 02:40:24.000000000 -0800
+++ openssl-0.9.8e/ssl/ssl_sess.c 2007-03-22 20:23:19.000000000 -0700
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c
--- openssl-0.9.8e.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8e/ssl/t1_ext.c 2007-03-22 20:23:19.000000000 -0700
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c
--- openssl-0.9.8e.orig/ssl/t1_lib.c 2007-01-21 08:07:25.000000000 -0800
+++ openssl-0.9.8e/ssl/t1_lib.c 2007-03-22 20:23:19.000000000 -0700
@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h
--- openssl-0.9.8e.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
+++ openssl-0.9.8e/ssl/tls1.h 2007-03-22 20:23:19.000000000 -0700
@@ -296,6 +296,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num
--- openssl-0.9.8e.orig/util/ssleay.num 2006-11-30 05:04:43.000000000 -0800
+++ openssl-0.9.8e/util/ssleay.num 2007-03-22 20:24:07.000000000 -0700
@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback
SSL_CTX_sess_get_new_cb 287 EXIST::FUNCTION:
SSL_CTX_get_client_cert_cb 288 EXIST::FUNCTION:
SSL_CTX_sess_get_remove_cb 289 EXIST::FUNCTION:
+SSL_set_hello_extension 290 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 291 EXIST::FUNCTION:
+SSL_set_session_secret_cb 292 EXIST::FUNCTION:

View File

@ -1,330 +0,0 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8g does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
--- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-31 03:28:51.000000000 +0300
+++ openssl-0.9.8g/ssl/s3_clnt.c 2008-04-15 17:11:46.000000000 +0300
@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
--- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 21:55:59.000000000 +0300
+++ openssl-0.9.8g/ssl/s3_srvr.c 2008-04-15 17:10:37.000000000 +0300
@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time=(unsigned long)time(NULL); /* Time */
+ pos=s->s3->server_random;
+ l2n(Time,pos);
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
- unsigned long l,Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d=p= &(buf[4]);
diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
--- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 10:42:38.000000000 +0300
+++ openssl-0.9.8g/ssl/ssl.h 2008-04-15 17:10:37.000000000 +0300
@@ -342,6 +342,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1004,6 +1007,14 @@ struct ssl_st
*/
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
+
+ /* TLS extensions */
+ TLS_EXTENSION *tls_extension;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
--- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 17:36:59.000000000 +0300
+++ openssl-0.9.8g/ssl/ssl_err.c 2008-04-15 17:10:37.000000000 +0300
@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
--- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 10:36:34.000000000 +0300
+++ openssl-0.9.8g/ssl/ssl_sess.c 2008-04-15 17:10:37.000000000 +0300
@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+
+ if(ext_data)
+ {
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ } else {
+ s->tls_extension->length = 0;
+ s->tls_extension->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
--- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 10:44:10.000000000 +0300
+++ openssl-0.9.8g/ssl/t1_lib.c 2008-04-15 17:10:37.000000000 +0300
@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
+#endif
ssl3_free(s);
}
@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tls_extension &&
+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
+ s->tls_extension->data)
+ {
+ ticklen = s->tls_extension->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick, s->tls_extension->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tls_extension &&
+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
+ s->tls_extension->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
+ skip_ext:
if ((extdatalen = ret-p-2)== 0)
return p;
@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ return 0;
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
--- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-28 04:12:44.000000000 +0300
+++ openssl-0.9.8g/ssl/tls1.h 2008-04-15 17:10:37.000000000 +0300
@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
--- openssl-0.9.8g.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
+++ openssl-0.9.8g/util/ssleay.num 2008-04-15 17:10:37.000000000 +0300
@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
SSL_set_SSL_CTX 290 EXIST::FUNCTION:
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT

View File

@ -1,344 +0,0 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8h does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c
--- openssl-0.9.8h.orig/ssl/s3_clnt.c 2008-05-28 10:29:27.000000000 +0300
+++ openssl-0.9.8h/ssl/s3_clnt.c 2008-05-29 10:44:25.000000000 +0300
@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s)
{
int ok;
long n;
- /* If we have no ticket or session ID is non-zero length (a match of
- * a non-zero session length would never reach here) it cannot be a
- * resumed session.
- */
- if (!s->session->tlsext_tick || s->session->session_id_length)
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c
--- openssl-0.9.8h.orig/ssl/s3_srvr.c 2008-04-30 19:11:32.000000000 +0300
+++ openssl-0.9.8h/ssl/s3_srvr.c 2008-05-28 18:49:34.000000000 +0300
@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time=(unsigned long)time(NULL); /* Time */
+ pos=s->s3->server_random;
+ l2n(Time,pos);
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
- unsigned long l,Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d=p= &(buf[4]);
diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h
--- openssl-0.9.8h.orig/ssl/ssl.h 2008-04-30 19:11:32.000000000 +0300
+++ openssl-0.9.8h/ssl/ssl.h 2008-05-28 18:49:34.000000000 +0300
@@ -343,6 +343,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1027,6 +1030,14 @@ struct ssl_st
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
+
+ /* TLS extensions */
+ TLS_EXTENSION *tls_extension;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c
--- openssl-0.9.8h.orig/ssl/ssl_err.c 2007-10-12 03:00:30.000000000 +0300
+++ openssl-0.9.8h/ssl/ssl_err.c 2008-05-28 18:49:34.000000000 +0300
@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c
--- openssl-0.9.8h.orig/ssl/ssl_sess.c 2007-10-17 20:30:15.000000000 +0300
+++ openssl-0.9.8h/ssl/ssl_sess.c 2008-05-28 18:49:34.000000000 +0300
@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+
+ if(ext_data)
+ {
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ } else {
+ s->tls_extension->length = 0;
+ s->tls_extension->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c
--- openssl-0.9.8h.orig/ssl/t1_lib.c 2008-05-28 10:26:33.000000000 +0300
+++ openssl-0.9.8h/ssl/t1_lib.c 2008-05-28 18:49:34.000000000 +0300
@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
+#endif
ssl3_free(s);
}
@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tls_extension &&
+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
+ s->tls_extension->data)
+ {
+ ticklen = s->tls_extension->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick, s->tls_extension->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tls_extension &&
+ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
+ s->tls_extension->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
+ skip_ext:
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
{
@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ return 0;
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h
--- openssl-0.9.8h.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300
+++ openssl-0.9.8h/ssl/tls1.h 2008-05-28 18:49:34.000000000 +0300
@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num
--- openssl-0.9.8h.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
+++ openssl-0.9.8h/util/ssleay.num 2008-05-28 18:49:34.000000000 +0300
@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
SSL_set_SSL_CTX 290 EXIST::FUNCTION:
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
+SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT

View File

@ -1,404 +0,0 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8i does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
Index: openssl-0.9.8i/ssl/s3_clnt.c
===================================================================
--- openssl-0.9.8i.orig/ssl/s3_clnt.c 2008-06-16 19:56:41.000000000 +0300
+++ openssl-0.9.8i/ssl/s3_clnt.c 2008-11-23 20:39:40.000000000 +0200
@@ -759,6 +759,21 @@
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher=pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
@@ -2701,11 +2716,8 @@
{
int ok;
long n;
- /* If we have no ticket or session ID is non-zero length (a match of
- * a non-zero session length would never reach here) it cannot be a
- * resumed session.
- */
- if (!s->session->tlsext_tick || s->session->session_id_length)
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
Index: openssl-0.9.8i/ssl/s3_srvr.c
===================================================================
--- openssl-0.9.8i.orig/ssl/s3_srvr.c 2008-09-14 21:16:09.000000000 +0300
+++ openssl-0.9.8i/ssl/s3_srvr.c 2008-11-23 20:37:40.000000000 +0200
@@ -959,6 +959,59 @@
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time=(unsigned long)time(NULL); /* Time */
+ pos=s->s3->server_random;
+ l2n(Time,pos);
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
@@ -1097,16 +1150,22 @@
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
- unsigned long l,Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d=p= &(buf[4]);
Index: openssl-0.9.8i/ssl/ssl_err.c
===================================================================
--- openssl-0.9.8i.orig/ssl/ssl_err.c 2008-08-13 22:44:44.000000000 +0300
+++ openssl-0.9.8i/ssl/ssl_err.c 2008-11-23 20:33:43.000000000 +0200
@@ -253,6 +253,7 @@
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
{0,NULL}
};
Index: openssl-0.9.8i/ssl/ssl.h
===================================================================
--- openssl-0.9.8i.orig/ssl/ssl.h 2008-08-13 22:44:44.000000000 +0300
+++ openssl-0.9.8i/ssl/ssl.h 2008-11-23 20:35:41.000000000 +0200
@@ -344,6 +344,7 @@
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -362,6 +363,9 @@
DECLARE_STACK_OF(SSL_CIPHER)
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1034,6 +1038,18 @@
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
+
+ /* TLS Session Ticket extension override */
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+ /* TLS Session Ticket extension callback */
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
+ void *tls_session_ticket_ext_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1632,6 +1648,15 @@
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1824,6 +1849,7 @@
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
Index: openssl-0.9.8i/ssl/ssl_sess.c
===================================================================
--- openssl-0.9.8i.orig/ssl/ssl_sess.c 2008-06-04 21:35:27.000000000 +0300
+++ openssl-0.9.8i/ssl/ssl_sess.c 2008-11-23 20:32:24.000000000 +0200
@@ -707,6 +707,61 @@
return(s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+ {
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+ }
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg)
+ {
+ if (s == NULL) return(0);
+ s->tls_session_ticket_ext_cb = cb;
+ s->tls_session_ticket_ext_cb_arg = arg;
+ return(1);
+ }
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+ {
+ if (s->version >= TLS1_VERSION)
+ {
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ s->tlsext_session_ticket = NULL;
+ }
+
+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+ if (!s->tlsext_session_ticket)
+ {
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (ext_data)
+ {
+ s->tlsext_session_ticket->length = ext_len;
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
+ }
+ else
+ {
+ s->tlsext_session_ticket->length = 0;
+ s->tlsext_session_ticket->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
Index: openssl-0.9.8i/ssl/t1_lib.c
===================================================================
--- openssl-0.9.8i.orig/ssl/t1_lib.c 2008-09-04 01:13:04.000000000 +0300
+++ openssl-0.9.8i/ssl/t1_lib.c 2008-11-23 20:31:20.000000000 +0200
@@ -106,6 +106,12 @@
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif
ssl3_free(s);
}
@@ -175,8 +181,23 @@
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
@@ -190,6 +211,7 @@
ret += ticklen;
}
}
+ skip_ext:
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
{
@@ -407,6 +429,15 @@
}
}
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
else if (type == TLSEXT_TYPE_status_request
&& s->ctx->tlsext_status_cb)
{
@@ -553,6 +584,12 @@
}
else if (type == TLSEXT_TYPE_session_ticket)
{
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
@@ -776,6 +813,15 @@
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
Index: openssl-0.9.8i/ssl/tls1.h
===================================================================
--- openssl-0.9.8i.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300
+++ openssl-0.9.8i/ssl/tls1.h 2008-11-23 20:22:38.000000000 +0200
@@ -398,6 +398,13 @@
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_session_ticket_ext_st
+ {
+ unsigned short length;
+ void *data;
+ };
+
#ifdef __cplusplus
}
#endif
Index: openssl-0.9.8i/util/ssleay.num
===================================================================
--- openssl-0.9.8i.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300
+++ openssl-0.9.8i/util/ssleay.num 2008-11-23 20:22:05.000000000 +0200
@@ -242,3 +242,5 @@
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT

View File

@ -4,15 +4,15 @@ the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8x does not enable TLS extension support by default, so it
OpenSSL 0.9.8za does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
--- openssl-0.9.8x.orig/ssl/s3_clnt.c 2011-12-26 21:38:28.000000000 +0200
+++ openssl-0.9.8x/ssl/s3_clnt.c 2012-07-07 10:46:31.501140621 +0300
@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s)
diff -upr openssl-0.9.8za.orig/ssl/s3_clnt.c openssl-0.9.8za/ssl/s3_clnt.c
--- openssl-0.9.8za.orig/ssl/s3_clnt.c 2014-06-05 11:09:26.000000000 +0300
+++ openssl-0.9.8za/ssl/s3_clnt.c 2014-06-05 20:37:09.221387312 +0300
@@ -767,6 +767,22 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
@ -27,6 +27,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
+ {
+ 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 */
@ -34,7 +35,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s)
@@ -2745,11 +2760,8 @@ int ssl3_check_finished(SSL *s)
{
int ok;
long n;
@ -48,10 +49,10 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
--- openssl-0.9.8x.orig/ssl/s3_srvr.c 2012-02-16 17:21:17.000000000 +0200
+++ openssl-0.9.8x/ssl/s3_srvr.c 2012-07-07 10:46:31.501140621 +0300
@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s)
diff -upr openssl-0.9.8za.orig/ssl/s3_srvr.c openssl-0.9.8za/ssl/s3_srvr.c
--- openssl-0.9.8za.orig/ssl/s3_srvr.c 2014-06-05 11:09:26.000000000 +0300
+++ openssl-0.9.8za/ssl/s3_srvr.c 2014-06-05 20:37:09.225387312 +0300
@@ -1011,6 +1011,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
@ -111,7 +112,7 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s)
@@ -1161,16 +1214,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
@ -135,10 +136,10 @@ diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
/* Do the message type and length last */
d=p= &(buf[4]);
diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
--- openssl-0.9.8x.orig/ssl/ssl_err.c 2012-03-12 16:50:55.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl_err.c 2012-07-07 10:46:31.501140621 +0300
@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
diff -upr openssl-0.9.8za.orig/ssl/ssl_err.c openssl-0.9.8za/ssl/ssl_err.c
--- openssl-0.9.8za.orig/ssl/ssl_err.c 2014-06-05 11:09:08.000000000 +0300
+++ openssl-0.9.8za/ssl/ssl_err.c 2014-06-05 20:37:09.225387312 +0300
@@ -265,6 +265,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"},
@ -146,9 +147,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
{0,NULL}
};
diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
--- openssl-0.9.8x.orig/ssl/ssl.h 2012-03-12 16:50:55.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl.h 2012-07-07 10:46:31.501140621 +0300
diff -upr openssl-0.9.8za.orig/ssl/ssl.h openssl-0.9.8za/ssl/ssl.h
--- openssl-0.9.8za.orig/ssl/ssl.h 2014-06-05 11:09:08.000000000 +0300
+++ openssl-0.9.8za/ssl/ssl.h 2014-06-05 20:37:09.229387312 +0300
@@ -344,6 +344,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
@ -167,7 +168,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1050,6 +1054,18 @@ struct ssl_st
@@ -1053,6 +1057,18 @@ struct ssl_st
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
@ -186,7 +187,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v
@@ -1668,6 +1684,15 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
@ -202,7 +203,7 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void);
@@ -1872,6 +1897,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
@ -210,9 +211,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
--- openssl-0.9.8x.orig/ssl/ssl_sess.c 2010-02-01 18:48:40.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl_sess.c 2012-07-07 10:46:31.501140621 +0300
diff -upr openssl-0.9.8za.orig/ssl/ssl_sess.c openssl-0.9.8za/ssl/ssl_sess.c
--- openssl-0.9.8za.orig/ssl/ssl_sess.c 2014-06-05 11:09:08.000000000 +0300
+++ openssl-0.9.8za/ssl/ssl_sess.c 2014-06-05 20:37:09.229387312 +0300
@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
@ -275,9 +276,9 @@ diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
--- openssl-0.9.8x.orig/ssl/t1_lib.c 2012-01-04 16:25:10.000000000 +0200
+++ openssl-0.9.8x/ssl/t1_lib.c 2012-07-07 10:47:31.153140501 +0300
diff -upr openssl-0.9.8za.orig/ssl/t1_lib.c openssl-0.9.8za/ssl/t1_lib.c
--- openssl-0.9.8za.orig/ssl/t1_lib.c 2014-06-05 11:09:08.000000000 +0300
+++ openssl-0.9.8za/ssl/t1_lib.c 2014-06-05 20:37:09.229387312 +0300
@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
@ -323,7 +324,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
s->version != DTLS1_VERSION)
@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
@@ -574,6 +596,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
return 0;
renegotiate_seen = 1;
}
@ -339,7 +340,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
{
@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
@@ -751,6 +782,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
}
else if (type == TLSEXT_TYPE_session_ticket)
{
@ -352,7 +353,7 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned
@@ -1043,6 +1080,15 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
@ -368,10 +369,10 @@ diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
--- openssl-0.9.8x.orig/ssl/tls1.h 2009-11-08 16:51:54.000000000 +0200
+++ openssl-0.9.8x/ssl/tls1.h 2012-07-07 10:46:31.501140621 +0300
@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
diff -upr openssl-0.9.8za.orig/ssl/tls1.h openssl-0.9.8za/ssl/tls1.h
--- openssl-0.9.8za.orig/ssl/tls1.h 2014-06-05 11:09:08.000000000 +0300
+++ openssl-0.9.8za/ssl/tls1.h 2014-06-05 20:37:09.229387312 +0300
@@ -415,6 +415,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
@ -385,9 +386,9 @@ diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
#ifdef __cplusplus
}
#endif
diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num
--- openssl-0.9.8x.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300
+++ openssl-0.9.8x/util/ssleay.num 2012-07-07 10:46:31.505140623 +0300
diff -upr openssl-0.9.8za.orig/util/ssleay.num openssl-0.9.8za/util/ssleay.num
--- openssl-0.9.8za.orig/util/ssleay.num 2014-06-05 12:38:45.000000000 +0300
+++ openssl-0.9.8za/util/ssleay.num 2014-06-05 20:37:09.229387312 +0300
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT

View File

@ -1,374 +0,0 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
NOTE: This patch (without SSL_set_hello_extension() wrapper) was
merged into the upstream OpenSSL 0.9.9 tree and as such, an external
patch for EAP-FAST support is not needed anymore.
Index: openssl-SNAP-20081111/ssl/s3_clnt.c
===================================================================
--- openssl-SNAP-20081111.orig/ssl/s3_clnt.c
+++ openssl-SNAP-20081111/ssl/s3_clnt.c
@@ -788,6 +788,23 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key,
+ &s->session->master_key_length,
+ NULL, &pref_cipher,
+ s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher = pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s, p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
@@ -2927,11 +2944,8 @@ static int ssl3_check_finished(SSL *s)
{
int ok;
long n;
- /* If we have no ticket or session ID is non-zero length (a match of
- * a non-zero session length would never reach here) it cannot be a
- * resumed session.
- */
- if (!s->session->tlsext_tick || s->session->session_id_length)
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
Index: openssl-SNAP-20081111/ssl/s3_srvr.c
===================================================================
--- openssl-SNAP-20081111.orig/ssl/s3_srvr.c
+++ openssl-SNAP-20081111/ssl/s3_srvr.c
@@ -1010,6 +1010,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time=(unsigned long)time(NULL); /* Time */
+ pos=s->s3->server_random;
+ l2n(Time,pos);
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/* Worst case, we will use the NULL compression, but if we have other
@@ -1134,16 +1187,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
- unsigned long l,Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d=p= &(buf[4]);
Index: openssl-SNAP-20081111/ssl/ssl_err.c
===================================================================
--- openssl-SNAP-20081111.orig/ssl/ssl_err.c
+++ openssl-SNAP-20081111/ssl/ssl_err.c
@@ -263,6 +263,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
{0,NULL}
};
Index: openssl-SNAP-20081111/ssl/ssl.h
===================================================================
--- openssl-SNAP-20081111.orig/ssl/ssl.h
+++ openssl-SNAP-20081111/ssl/ssl.h
@@ -355,6 +355,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -378,6 +379,8 @@ typedef struct ssl_cipher_st
DECLARE_STACK_OF(SSL_CIPHER)
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1145,6 +1148,13 @@ struct ssl_st
void *tlsext_opaque_prf_input;
size_t tlsext_opaque_prf_input_len;
+ /* TLS Session Ticket extension override */
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1746,6 +1756,16 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* NOTE: This function will be removed; it is only here for backwards
+ * compatibility for the API during testing. */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1948,6 +1968,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_PRF 284
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
Index: openssl-SNAP-20081111/ssl/ssl_sess.c
===================================================================
--- openssl-SNAP-20081111.orig/ssl/ssl_sess.c
+++ openssl-SNAP-20081111/ssl/ssl_sess.c
@@ -834,6 +834,62 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+ {
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+ }
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+ {
+ if (s->version >= TLS1_VERSION)
+ {
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ s->tlsext_session_ticket = NULL;
+ }
+
+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+ if (!s->tlsext_session_ticket)
+ {
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (ext_data)
+ {
+ s->tlsext_session_ticket->length = ext_len;
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
+ }
+ else
+ {
+ s->tlsext_session_ticket->length = 0;
+ s->tlsext_session_ticket->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+/* NOTE: This function will be removed; it is only here for backwards
+ * compatibility for the API during testing. */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+ {
+ if (ext_type != TLSEXT_TYPE_session_ticket)
+ return 0;
+
+ return SSL_set_session_ticket_ext(s, ext_data, ext_len);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
Index: openssl-SNAP-20081111/ssl/t1_lib.c
===================================================================
--- openssl-SNAP-20081111.orig/ssl/t1_lib.c
+++ openssl-SNAP-20081111/ssl/t1_lib.c
@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif /* OPENSSL_NO_TLSEXT */
ssl3_free(s);
}
@@ -357,8 +363,23 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
@@ -371,6 +392,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
+ skip_ext:
#ifdef TLSEXT_TYPE_opaque_prf_input
if (s->s3->client_opaque_prf_input != NULL)
@@ -1435,6 +1457,15 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
Index: openssl-SNAP-20081111/ssl/tls1.h
===================================================================
--- openssl-SNAP-20081111.orig/ssl/tls1.h
+++ openssl-SNAP-20081111/ssl/tls1.h
@@ -512,6 +512,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS Session Ticket extension struct */
+struct tls_session_ticket_ext_st
+ {
+ unsigned short length;
+ void *data;
+ };
+
#ifdef __cplusplus
}
#endif
Index: openssl-SNAP-20081111/util/ssleay.num
===================================================================
--- openssl-SNAP-20081111.orig/util/ssleay.num
+++ openssl-SNAP-20081111/util/ssleay.num
@@ -254,3 +254,5 @@ PEM_read_bio_SSL_SESSION
SSL_CTX_set_psk_server_callback 303 EXIST::FUNCTION:PSK
SSL_get_psk_identity 304 EXIST::FUNCTION:PSK
PEM_write_SSL_SESSION 305 EXIST:!WIN16:FUNCTION:
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT

View File

@ -10,7 +10,8 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@ -44,19 +45,26 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
if (msg == NULL) {
printf("Could not create net RADIUS packet\n");
wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return NULL;
}
if (sta) {
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
os_snprintf(buf, sizeof(buf), "%08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Acct-Session-Id\n");
goto fail;
if ((hapd->conf->wpa & 2) &&
!hapd->conf->disable_pmksa_caching &&
sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
os_snprintf(buf, sizeof(buf), "%08X+%08X",
sta->eapol_sm->acct_multi_session_id_hi,
sta->eapol_sm->acct_multi_session_id_lo);
if (!radius_msg_add_attr(
msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_INFO,
"Could not add Acct-Multi-Session-Id");
goto fail;
}
}
} else {
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
@ -64,7 +72,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
printf("Could not add Acct-Status-Type\n");
wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
goto fail;
}
@ -74,7 +82,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
printf("Could not add Acct-Authentic\n");
wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
goto fail;
}
@ -99,7 +107,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
len)) {
printf("Could not add User-Name\n");
wpa_printf(MSG_INFO, "Could not add User-Name");
goto fail;
}
}
@ -117,7 +125,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
val, len)) {
printf("Could not add Class\n");
wpa_printf(MSG_INFO, "Could not add Class");
goto fail;
}
}
@ -202,7 +210,6 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
struct os_time t;
int interval;
if (sta->acct_session_started)
@ -213,8 +220,7 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
"starting accounting session %08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
os_get_time(&t);
sta->acct_session_start = t.sec;
os_get_reltime(&sta->acct_session_start);
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
@ -244,6 +250,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
struct os_reltime now_r, diff;
struct os_time now;
u32 gigawords;
@ -254,14 +261,16 @@ static void accounting_sta_report(struct hostapd_data *hapd,
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
if (!msg) {
printf("Could not create RADIUS Accounting message\n");
wpa_printf(MSG_INFO, "Could not create RADIUS Accounting message");
return;
}
os_get_reltime(&now_r);
os_get_time(&now);
os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
now.sec - sta->acct_session_start)) {
printf("Could not add Acct-Session-Time\n");
diff.sec)) {
wpa_printf(MSG_INFO, "Could not add Acct-Session-Time");
goto fail;
}
@ -269,19 +278,19 @@ static void accounting_sta_report(struct hostapd_data *hapd,
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_PACKETS,
data.rx_packets)) {
printf("Could not add Acct-Input-Packets\n");
wpa_printf(MSG_INFO, "Could not add Acct-Input-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
data.tx_packets)) {
printf("Could not add Acct-Output-Packets\n");
wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
data.rx_bytes)) {
printf("Could not add Acct-Input-Octets\n");
wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
goto fail;
}
gigawords = sta->acct_input_gigawords;
@ -292,13 +301,13 @@ static void accounting_sta_report(struct hostapd_data *hapd,
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Input-Gigawords\n");
wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
data.tx_bytes)) {
printf("Could not add Acct-Output-Octets\n");
wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
goto fail;
}
gigawords = sta->acct_output_gigawords;
@ -309,14 +318,14 @@ static void accounting_sta_report(struct hostapd_data *hapd,
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Output-Gigawords\n");
wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
goto fail;
}
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
now.sec)) {
printf("Could not add Event-Timestamp\n");
wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
goto fail;
}
@ -326,7 +335,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
if (stop && cause &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
cause)) {
printf("Could not add Acct-Terminate-Cause\n");
wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
goto fail;
}
@ -400,13 +409,12 @@ accounting_receive(struct radius_msg *msg, struct radius_msg *req,
void *data)
{
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
printf("Unknown RADIUS message code\n");
wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
printf("Incoming RADIUS packet did not have correct "
"Authenticator - dropped\n");
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@ -432,7 +440,7 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
{
printf("Could not add Acct-Terminate-Cause\n");
wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
radius_msg_free(msg);
return;
}

949
contrib/wpa/src/ap/acs.c Normal file
View File

@ -0,0 +1,949 @@
/*
* ACS - Automatic Channel Selection module
* Copyright (c) 2011, Atheros Communications
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <math.h>
#include "utils/common.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
#include "acs.h"
/*
* Automatic Channel Selection
* ===========================
*
* More info at
* ------------
* http://wireless.kernel.org/en/users/Documentation/acs
*
* How to use
* ----------
* - make sure you have CONFIG_ACS=y in hostapd's .config
* - use channel=0 or channel=acs to enable ACS
*
* How does it work
* ----------------
* 1. passive scans are used to collect survey data
* (it is assumed that scan trigger collection of survey data in driver)
* 2. interference factor is calculated for each channel
* 3. ideal channel is picked depending on channel width by using adjacent
* channel interference factors
*
* Known limitations
* -----------------
* - Current implementation depends heavily on the amount of time willing to
* spend gathering survey data during hostapd startup. Short traffic bursts
* may be missed and a suboptimal channel may be picked.
* - Ideal channel may end up overlapping a channel with 40 MHz intolerant BSS
*
* Todo / Ideas
* ------------
* - implement other interference computation methods
* - BSS/RSSI based
* - spectral scan based
* (should be possibly to hook this up with current ACS scans)
* - add wpa_supplicant support (for P2P)
* - collect a histogram of interference over time allowing more educated
* guess about an ideal channel (perhaps CSA could be used to migrate AP to a
* new "better" channel while running)
* - include neighboring BSS scan to avoid conflicts with 40 MHz intolerant BSSs
* when choosing the ideal channel
*
* Survey interference factor implementation details
* -------------------------------------------------
* Generic interference_factor in struct hostapd_channel_data is used.
*
* The survey interference factor is defined as the ratio of the
* observed busy time over the time we spent on the channel,
* this value is then amplified by the observed noise floor on
* the channel in comparison to the lowest noise floor observed
* on the entire band.
*
* This corresponds to:
* ---
* (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
* ---
*
* The coefficient of 2 reflects the way power in "far-field"
* radiation decreases as the square of distance from the antenna [1].
* What this does is it decreases the observed busy time ratio if the
* noise observed was low but increases it if the noise was high,
* proportionally to the way "far field" radiation changes over
* distance.
*
* If channel busy time is not available the fallback is to use channel RX time.
*
* Since noise floor is in dBm it is necessary to convert it into Watts so that
* combined channel interference (e.g., HT40, which uses two channels) can be
* calculated easily.
* ---
* (busy time - tx time) / (active time - tx time) *
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
* ---
*
* However to account for cases where busy/rx time is 0 (channel load is then
* 0%) channel noise floor signal power is combined into the equation so a
* channel with lower noise floor is preferred. The equation becomes:
* ---
* 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
* ---
*
* All this "interference factor" is purely subjective and only time
* will tell how usable this is. By using the minimum noise floor we
* remove any possible issues due to card calibration. The computation
* of the interference factor then is dependent on what the card itself
* picks up as the minimum noise, not an actual real possible card
* noise value.
*
* Total interference computation details
* --------------------------------------
* The above channel interference factor is calculated with no respect to
* target operational bandwidth.
*
* To find an ideal channel the above data is combined by taking into account
* the target operational bandwidth and selected band. E.g., on 2.4 GHz channels
* overlap with 20 MHz bandwidth, but there is no overlap for 20 MHz bandwidth
* on 5 GHz.
*
* Each valid and possible channel spec (i.e., channel + width) is taken and its
* interference factor is computed by summing up interferences of each channel
* it overlaps. The one with least total interference is picked up.
*
* Note: This implies base channel interference factor must be non-negative
* allowing easy summing up.
*
* Example ACS analysis printout
* -----------------------------
*
* ACS: Trying survey-based ACS
* ACS: Survey analysis for channel 1 (2412 MHz)
* ACS: 1: min_nf=-113 interference_factor=0.0802469 nf=-113 time=162 busy=0 rx=13
* ACS: 2: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
* ACS: 3: min_nf=-113 interference_factor=0.0679012 nf=-113 time=162 busy=0 rx=11
* ACS: 4: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
* ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
* ACS: * interference factor average: 0.0557166
* ACS: Survey analysis for channel 2 (2417 MHz)
* ACS: 1: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
* ACS: 2: min_nf=-113 interference_factor=0.0246914 nf=-113 time=162 busy=0 rx=4
* ACS: 3: min_nf=-113 interference_factor=0.037037 nf=-113 time=162 busy=0 rx=6
* ACS: 4: min_nf=-113 interference_factor=0.149068 nf=-113 time=161 busy=0 rx=24
* ACS: 5: min_nf=-113 interference_factor=0.0248447 nf=-113 time=161 busy=0 rx=4
* ACS: * interference factor average: 0.050832
* ACS: Survey analysis for channel 3 (2422 MHz)
* ACS: 1: min_nf=-113 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
* ACS: 2: min_nf=-113 interference_factor=0.0185185 nf=-113 time=162 busy=0 rx=3
* ACS: 3: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
* ACS: 4: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
* ACS: 5: min_nf=-113 interference_factor=0.0186335 nf=-113 time=161 busy=0 rx=3
* ACS: * interference factor average: 0.0148838
* ACS: Survey analysis for channel 4 (2427 MHz)
* ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
* ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
* ACS: 4: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
* ACS: 5: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
* ACS: * interference factor average: 0.0160801
* ACS: Survey analysis for channel 5 (2432 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.409938 nf=-113 time=161 busy=0 rx=66
* ACS: 2: min_nf=-114 interference_factor=0.0432099 nf=-113 time=162 busy=0 rx=7
* ACS: 3: min_nf=-114 interference_factor=0.0124224 nf=-113 time=161 busy=0 rx=2
* ACS: 4: min_nf=-114 interference_factor=0.677019 nf=-113 time=161 busy=0 rx=109
* ACS: 5: min_nf=-114 interference_factor=0.0186335 nf=-114 time=161 busy=0 rx=3
* ACS: * interference factor average: 0.232244
* ACS: Survey analysis for channel 6 (2437 MHz)
* ACS: 1: min_nf=-113 interference_factor=0.552795 nf=-113 time=161 busy=0 rx=89
* ACS: 2: min_nf=-113 interference_factor=0.0807453 nf=-112 time=161 busy=0 rx=13
* ACS: 3: min_nf=-113 interference_factor=0.0310559 nf=-113 time=161 busy=0 rx=5
* ACS: 4: min_nf=-113 interference_factor=0.434783 nf=-112 time=161 busy=0 rx=70
* ACS: 5: min_nf=-113 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
* ACS: * interference factor average: 0.232298
* ACS: Survey analysis for channel 7 (2442 MHz)
* ACS: 1: min_nf=-113 interference_factor=0.440994 nf=-112 time=161 busy=0 rx=71
* ACS: 2: min_nf=-113 interference_factor=0.385093 nf=-113 time=161 busy=0 rx=62
* ACS: 3: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
* ACS: 4: min_nf=-113 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
* ACS: 5: min_nf=-113 interference_factor=0.0745342 nf=-113 time=161 busy=0 rx=12
* ACS: * interference factor average: 0.195031
* ACS: Survey analysis for channel 8 (2447 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.0496894 nf=-112 time=161 busy=0 rx=8
* ACS: 2: min_nf=-114 interference_factor=0.0496894 nf=-114 time=161 busy=0 rx=8
* ACS: 3: min_nf=-114 interference_factor=0.0372671 nf=-113 time=161 busy=0 rx=6
* ACS: 4: min_nf=-114 interference_factor=0.12963 nf=-113 time=162 busy=0 rx=21
* ACS: 5: min_nf=-114 interference_factor=0.166667 nf=-114 time=162 busy=0 rx=27
* ACS: * interference factor average: 0.0865885
* ACS: Survey analysis for channel 9 (2452 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.0124224 nf=-114 time=161 busy=0 rx=2
* ACS: 2: min_nf=-114 interference_factor=0.0310559 nf=-114 time=161 busy=0 rx=5
* ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
* ACS: 4: min_nf=-114 interference_factor=0.00617284 nf=-114 time=162 busy=0 rx=1
* ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: * interference factor average: 0.00993022
* ACS: Survey analysis for channel 10 (2457 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
* ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
* ACS: 3: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
* ACS: 4: min_nf=-114 interference_factor=0.0493827 nf=-114 time=162 busy=0 rx=8
* ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: * interference factor average: 0.0136033
* ACS: Survey analysis for channel 11 (2462 MHz)
* ACS: 1: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=161 busy=0 rx=0
* ACS: 2: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
* ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=161 busy=0 rx=0
* ACS: 4: min_nf=-114 interference_factor=0.0432099 nf=-114 time=162 busy=0 rx=7
* ACS: 5: min_nf=-114 interference_factor=0.0925926 nf=-114 time=162 busy=0 rx=15
* ACS: * interference factor average: 0.0271605
* ACS: Survey analysis for channel 12 (2467 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.0621118 nf=-113 time=161 busy=0 rx=10
* ACS: 2: min_nf=-114 interference_factor=0.00621118 nf=-114 time=161 busy=0 rx=1
* ACS: 3: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
* ACS: 4: min_nf=-114 interference_factor=2.51189e-23 nf=-113 time=162 busy=0 rx=0
* ACS: 5: min_nf=-114 interference_factor=0.00617284 nf=-113 time=162 busy=0 rx=1
* ACS: * interference factor average: 0.0148992
* ACS: Survey analysis for channel 13 (2472 MHz)
* ACS: 1: min_nf=-114 interference_factor=0.0745342 nf=-114 time=161 busy=0 rx=12
* ACS: 2: min_nf=-114 interference_factor=0.0555556 nf=-114 time=162 busy=0 rx=9
* ACS: 3: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: 4: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: 5: min_nf=-114 interference_factor=1.58489e-23 nf=-114 time=162 busy=0 rx=0
* ACS: * interference factor average: 0.0260179
* ACS: Survey analysis for selected bandwidth 20MHz
* ACS: * channel 1: total interference = 0.121432
* ACS: * channel 2: total interference = 0.137512
* ACS: * channel 3: total interference = 0.369757
* ACS: * channel 4: total interference = 0.546338
* ACS: * channel 5: total interference = 0.690538
* ACS: * channel 6: total interference = 0.762242
* ACS: * channel 7: total interference = 0.756092
* ACS: * channel 8: total interference = 0.537451
* ACS: * channel 9: total interference = 0.332313
* ACS: * channel 10: total interference = 0.152182
* ACS: * channel 11: total interference = 0.0916111
* ACS: * channel 12: total interference = 0.0816809
* ACS: * channel 13: total interference = 0.0680776
* ACS: Ideal channel is 13 (2472 MHz) with total interference factor of 0.0680776
*
* [1] http://en.wikipedia.org/wiki/Near_and_far_field
*/
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)
{
struct freq_survey *survey, *tmp;
if (dl_list_empty(&chan->survey_list))
return;
dl_list_for_each_safe(survey, tmp, &chan->survey_list,
struct freq_survey, list) {
dl_list_del(&survey->list);
os_free(survey);
}
}
static void acs_cleanup(struct hostapd_iface *iface)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
dl_list_init(&chan->survey_list);
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
}
static void acs_fail(struct hostapd_iface *iface)
{
wpa_printf(MSG_ERROR, "ACS: Failed to start");
acs_cleanup(iface);
hostapd_disable_iface(iface);
}
static long double
acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
{
long double factor, busy, total;
if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY)
busy = survey->channel_time_busy;
else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
busy = survey->channel_time_rx;
else {
/* This shouldn't really happen as survey data is checked in
* acs_sanity_check() */
wpa_printf(MSG_ERROR, "ACS: Survey data missing");
return 0;
}
total = survey->channel_time;
if (survey->filled & SURVEY_HAS_CHAN_TIME_TX) {
busy -= survey->channel_time_tx;
total -= survey->channel_time_tx;
}
/* TODO: figure out the best multiplier for noise floor base */
factor = pow(10, survey->nf / 5.0L) +
(busy / total) *
pow(2, pow(10, (long double) survey->nf / 10.0L) -
pow(10, (long double) min_nf / 10.0L));
return factor;
}
static void
acs_survey_chan_interference_factor(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
struct freq_survey *survey;
unsigned int i = 0;
long double int_factor = 0;
unsigned count = 0;
if (dl_list_empty(&chan->survey_list))
return;
if (chan->flag & HOSTAPD_CHAN_DISABLED)
return;
chan->interference_factor = 0;
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,
survey->nf, (unsigned long) survey->channel_time,
(unsigned long) survey->channel_time_busy,
(unsigned long) survey->channel_time_rx);
}
if (!count)
return;
chan->interference_factor /= count;
}
static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
157, 184, 192 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
return 1;
return 0;
}
static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
return 1;
return 0;
}
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_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_INFO,
"ACS: Survey is missing RX and busy time (at least one is required)");
return 0;
}
return 1;
}
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)) {
ret = 1;
break;
}
ret = 0;
}
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;
}
static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
{
int i;
struct hostapd_channel_data *chan;
int valid = 0;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (!acs_survey_list_is_sufficient(chan))
continue;
valid++;
}
/* We need at least survey data for one channel */
return !!valid;
}
static int acs_usable_chan(struct hostapd_channel_data *chan)
{
if (dl_list_empty(&chan->survey_list))
return 0;
if (chan->flag & HOSTAPD_CHAN_DISABLED)
return 0;
if (!acs_survey_list_is_sufficient(chan))
return 0;
return 1;
}
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
int *entry;
if (!iface->conf->chanlist)
return 1;
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
if (*entry == chan->chan)
return 1;
}
return 0;
}
static void acs_survey_all_chans_intereference_factor(
struct hostapd_iface *iface)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
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);
acs_survey_chan_interference_factor(iface, chan);
wpa_printf(MSG_DEBUG, "ACS: * interference factor average: %Lg",
chan->interference_factor);
}
}
static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
int freq)
{
struct hostapd_channel_data *chan;
int i;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (chan->freq == freq)
return chan;
}
return NULL;
}
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
* option (survey, BSS, spectral, ...). chan->interference factor must be
* summable (i.e., must be always greater than zero).
*/
static struct hostapd_channel_data *
acs_find_ideal_chan(struct hostapd_iface *iface)
{
struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
*rand_chan = NULL;
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
unsigned int k;
/* TODO: HT40- support */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel == -1) {
wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
return NULL;
}
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel)
n_chans = 2;
if (iface->conf->ieee80211ac &&
iface->conf->vht_oper_chwidth == 1)
n_chans = 4;
/* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
n_chans == 1 ? 20 :
n_chans == 2 ? 40 :
n_chans == 4 ? 80 :
-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 */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) {
wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40",
chan->chan);
continue;
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211ac &&
iface->conf->vht_oper_chwidth == 1 &&
!acs_usable_vht80_chan(chan)) {
wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
chan->chan);
continue;
}
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)) {
factor += adj_chan->interference_factor;
total_weight += 1;
}
}
if (j != n_chans) {
wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth",
chan->chan);
continue;
}
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
if (is_24ghz_mode(iface->current_mode->mode)) {
for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
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 += 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 += 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 += ACS_NEXT_ADJ_WEIGHT *
adj_chan->interference_factor;
total_weight += ACS_NEXT_ADJ_WEIGHT;
}
}
}
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)) {
ideal_factor = factor;
ideal_chan = chan;
}
/* This channel would at least be usable */
if (!rand_chan)
rand_chan = chan;
}
if (ideal_chan) {
wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
ideal_chan->chan, ideal_chan->freq, ideal_factor);
return ideal_chan;
}
return rand_chan;
}
static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
{
int offset;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
break;
case VHT_CHANWIDTH_80MHZ:
offset = 6;
break;
default:
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
return;
}
iface->conf->vht_oper_centr_freq_seg0_idx =
iface->conf->channel + offset;
}
static int acs_study_survey_based(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "ACS: Trying survey-based ACS");
if (!iface->chans_surveyed) {
wpa_printf(MSG_ERROR, "ACS: Unable to collect survey data");
return -1;
}
if (!acs_surveys_are_sufficient(iface)) {
wpa_printf(MSG_ERROR, "ACS: Surveys have insufficient data");
return -1;
}
acs_survey_all_chans_intereference_factor(iface);
return 0;
}
static int acs_study_options(struct hostapd_iface *iface)
{
int err;
err = acs_study_survey_based(iface);
if (err == 0)
return 0;
/* TODO: If no surveys are available/sufficient this is a good
* place to fallback to BSS-based ACS */
return -1;
}
static void acs_study(struct hostapd_iface *iface)
{
struct hostapd_channel_data *ideal_chan;
int err;
err = acs_study_options(iface);
if (err < 0) {
wpa_printf(MSG_ERROR, "ACS: All study options have failed");
goto fail;
}
ideal_chan = acs_find_ideal_chan(iface);
if (!ideal_chan) {
wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
err = -1;
goto fail;
}
iface->conf->channel = ideal_chan->chan;
if (iface->conf->ieee80211ac)
acs_adjust_vht_center_freq(iface);
err = 0;
fail:
/*
* hostapd_setup_interface_complete() will return -1 on failure,
* 0 on success and 0 is HOSTAPD_CHAN_VALID :)
*/
if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
acs_cleanup(iface);
return;
}
/* This can possibly happen if channel parameters (secondary
* channel, center frequencies) are misconfigured */
wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
acs_fail(iface);
}
static void acs_scan_complete(struct hostapd_iface *iface)
{
int err;
iface->scan_cb = NULL;
wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
iface->conf->acs_num_scans);
err = hostapd_drv_get_survey(iface->bss[0], 0);
if (err) {
wpa_printf(MSG_ERROR, "ACS: Failed to get survey data");
goto fail;
}
if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
err = acs_request_scan(iface);
if (err) {
wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
goto fail;
}
return;
}
acs_study(iface);
return;
fail:
hostapd_acs_completed(iface, 1);
acs_fail(iface);
}
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
struct hostapd_channel_data *chan;
int i, *freq;
os_memset(&params, 0, sizeof(params));
params.freqs = os_calloc(iface->current_mode->num_channels + 1,
sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
*freq++ = chan->freq;
}
*freq = 0;
iface->scan_cb = acs_scan_complete;
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans);
if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
acs_cleanup(iface);
os_free(params.freqs);
return -1;
}
os_free(params.freqs);
return 0;
}
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
{
int err;
wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
wpa_printf(MSG_INFO, "ACS: Offloading to driver");
err = hostapd_drv_do_acs(iface->bss[0]);
if (err)
return HOSTAPD_CHAN_INVALID;
return HOSTAPD_CHAN_ACS;
}
acs_cleanup(iface);
err = acs_request_scan(iface);
if (err < 0)
return HOSTAPD_CHAN_INVALID;
hostapd_set_state(iface, HAPD_IFACE_ACS);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_STARTED);
return HOSTAPD_CHAN_ACS;
}

27
contrib/wpa/src/ap/acs.h Normal file
View File

@ -0,0 +1,27 @@
/*
* ACS - Automatic Channel Selection module
* Copyright (c) 2011, Atheros Communications
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef ACS_H
#define ACS_H
#ifdef CONFIG_ACS
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
#else /* CONFIG_ACS */
static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
{
wpa_printf(MSG_ERROR, "ACS was disabled on your build, rebuild hostapd with CONFIG_ACS=y or set channel");
return HOSTAPD_CHAN_INVALID;
}
#endif /* CONFIG_ACS */
#endif /* ACS_H */

View File

@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -73,6 +73,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
@ -89,6 +90,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
bss->sae_anti_clogging_threshold = 5;
}
@ -104,9 +107,9 @@ struct hostapd_config * hostapd_config_defaults(void)
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
{ aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
{ aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
@ -128,9 +131,17 @@ struct hostapd_config * hostapd_config_defaults(void)
os_free(bss);
return NULL;
}
conf->bss = os_calloc(1, sizeof(struct hostapd_bss_config *));
if (conf->bss == NULL) {
os_free(conf);
os_free(bss);
return NULL;
}
conf->bss[0] = bss;
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
os_free(conf->bss);
os_free(conf);
os_free(bss);
return NULL;
@ -139,12 +150,13 @@ struct hostapd_config * hostapd_config_defaults(void)
hostapd_config_defaults_bss(bss);
conf->num_bss = 1;
conf->bss = bss;
conf->beacon_int = 100;
conf->rts_threshold = -1; /* use driver default: 2347 */
conf->fragm_threshold = -1; /* user driver default: 2346 */
conf->send_probe_response = 1;
/* Set to invalid value means do not add Power Constraint IE */
conf->local_pwr_constraint = -1;
conf->wmm_ac_params[0] = ac_be;
conf->wmm_ac_params[1] = ac_bk;
@ -161,6 +173,18 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
#ifdef CONFIG_TESTING_OPTIONS
conf->ignore_probe_probability = 0.0;
conf->ignore_auth_probability = 0.0;
conf->ignore_assoc_probability = 0.0;
conf->ignore_reassoc_probability = 0.0;
conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
return conf;
}
@ -315,20 +339,6 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
}
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
{
int i;
if (a->idx != b->idx || a->default_len != b->default_len)
return 1;
for (i = 0; i < NUM_WEP_KEYS; i++)
if (a->len[i] != b->len[i] ||
os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
return 1;
return 0;
}
static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
int num_servers)
{
@ -365,10 +375,11 @@ static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
}
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
os_free(user->password);
bin_clear_free(user->password, user->password_len);
os_free(user);
}
@ -377,28 +388,35 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
os_free(keys->key[i]);
bin_clear_free(keys->key[i], keys->len[i]);
keys->key[i] = NULL;
}
}
static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
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;
os_free(prev);
}
hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
os_free(conf->ssid.wpa_passphrase);
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
hostapd_config_free_wep(&conf->ssid.wep);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@ -413,15 +431,17 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
os_free(conf->eap_user_sqlite);
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
os_free(conf->erp_domain);
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
hostapd_config_free_radius(conf->radius->auth_servers,
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
if (conf->radius) {
hostapd_config_free_radius(conf->radius->auth_servers,
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
@ -430,29 +450,17 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->server_cert);
os_free(conf->private_key);
os_free(conf->private_key_passwd);
os_free(conf->ocsp_stapling_response);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
if (conf->ssid.dyn_vlan_keys) {
struct hostapd_ssid *ssid = &conf->ssid;
size_t i;
for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
if (ssid->dyn_vlan_keys[i] == NULL)
continue;
hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
os_free(ssid->dyn_vlan_keys[i]);
}
os_free(ssid->dyn_vlan_keys);
ssid->dyn_vlan_keys = NULL;
}
os_free(conf->time_zone);
#ifdef CONFIG_IEEE80211R
@ -495,6 +503,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
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);
@ -516,9 +530,36 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->hs20_wan_metrics);
os_free(conf->hs20_connection_capability);
os_free(conf->hs20_operating_class);
os_free(conf->hs20_icons);
if (conf->hs20_osu_providers) {
size_t i;
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
struct hs20_osu_provider *p;
size_t j;
p = &conf->hs20_osu_providers[i];
os_free(p->friendly_name);
os_free(p->server_uri);
os_free(p->method_list);
for (j = 0; j < p->icons_count; j++)
os_free(p->icons[j]);
os_free(p->icons);
os_free(p->osu_nai);
os_free(p->service_desc);
}
os_free(conf->hs20_osu_providers);
}
os_free(conf->subscr_remediation_url);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
os_free(conf->sae_groups);
os_free(conf->wowlan_triggers);
os_free(conf->server_id);
os_free(conf);
}
@ -534,10 +575,15 @@ void hostapd_config_free(struct hostapd_config *conf)
return;
for (i = 0; i < conf->num_bss; i++)
hostapd_config_free_bss(&conf->bss[i]);
hostapd_config_free_bss(conf->bss[i]);
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->chanlist);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
#endif /* CONFIG_ACS */
os_free(conf);
}
@ -594,11 +640,23 @@ int hostapd_rate_found(int *list, int rate)
}
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
{
struct hostapd_vlan *v = vlan;
while (v) {
if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
return 1;
v = v->next;
}
return 0;
}
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
{
struct hostapd_vlan *v = vlan;
while (v) {
if (v->vlan_id == vlan_id)
return v->ifname;
v = v->next;
}
@ -607,14 +665,30 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk)
const u8 *addr, const u8 *p2p_dev_addr,
const u8 *prev_psk)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
" p2p_dev_addr=" MACSTR " prev_psk=%p",
MAC2STR(addr), MAC2STR(p2p_dev_addr), prev_psk);
addr = NULL; /* Use P2P Device Address for matching */
} else {
wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
" prev_psk=%p",
MAC2STR(addr), prev_psk);
}
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
if (next_ok &&
(psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
(psk->group ||
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
(!addr && p2p_dev_addr &&
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
0)))
return psk->psk;
if (psk->psk == prev_psk)
@ -623,3 +697,250 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
return NULL;
}
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
{
if (full_config && bss->ieee802_1x && !bss->eap_server &&
!bss->radius->auth_servers) {
wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
"EAP authenticator configured).");
return -1;
}
if (bss->wpa) {
int wep, i;
wep = bss->default_wep_key_len > 0 ||
bss->individual_wep_key_len > 0;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (bss->ssid.wep.keys_set) {
wep = 1;
break;
}
}
if (wep) {
wpa_printf(MSG_ERROR, "WEP configuration in a WPA network is not supported");
return -1;
}
}
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
"RADIUS checking (macaddr_acl=2) enabled.");
return -1;
}
if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
bss->ssid.wpa_psk_file == NULL &&
(bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
"is not configured.");
return -1;
}
if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
size_t i;
for (i = 0; i < conf->num_bss; i++) {
if (conf->bss[i] != bss &&
(hostapd_mac_comp(conf->bss[i]->bssid,
bss->bssid) == 0)) {
wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
" on interface '%s' and '%s'.",
MAC2STR(bss->bssid),
conf->bss[i]->iface, bss->iface);
return -1;
}
}
}
#ifdef CONFIG_IEEE80211R
if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
(bss->nas_identifier == NULL ||
os_strlen(bss->nas_identifier) < 1 ||
os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
"nas_identifier to be configured as a 1..48 octet "
"string");
return -1;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities");
}
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
"configuration forced WPS to be disabled");
bss->wps_state = 0;
}
if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled");
bss->wps_state = 0;
}
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
!(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
"WPA2/CCMP forced WPS to be disabled");
bss->wps_state = 0;
}
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
if (full_config && bss->hs20 &&
(!(bss->wpa & 2) ||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 |
WPA_CIPHER_GCMP_256)))) {
wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
"configuration is required for Hotspot 2.0 "
"functionality");
return -1;
}
#endif /* CONFIG_HS20 */
return 0;
}
int hostapd_config_check(struct hostapd_config *conf, int full_config)
{
size_t i;
if (full_config && conf->ieee80211d &&
(!conf->country[0] || !conf->country[1])) {
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
"setting the country_code");
return -1;
}
if (full_config && conf->ieee80211h && !conf->ieee80211d) {
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11h without "
"IEEE 802.11d enabled");
return -1;
}
if (full_config && conf->local_pwr_constraint != -1 &&
!conf->ieee80211d) {
wpa_printf(MSG_ERROR, "Cannot add Power Constraint element without Country element");
return -1;
}
if (full_config && conf->spectrum_mgmt_required &&
conf->local_pwr_constraint == -1) {
wpa_printf(MSG_ERROR, "Cannot set Spectrum Management bit without Country and Power Constraint elements");
return -1;
}
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
}
return 0;
}
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config)
{
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
bss->rsn_pairwise);
if (full_config) {
bss->radius->auth_server = bss->radius->auth_servers;
bss->radius->acct_server = bss->radius->acct_servers;
}
if (bss->wpa && bss->ieee802_1x) {
bss->ssid.security_policy = SECURITY_WPA;
} else if (bss->wpa) {
bss->ssid.security_policy = SECURITY_WPA_PSK;
} else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
} else if (full_config && bss->ssid.wep.keys_set) {
if (bss->ssid.wep.len[0] >= 13)
cipher = WPA_CIPHER_WEP104;
else
cipher = WPA_CIPHER_WEP40;
}
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
cipher = WPA_CIPHER_WEP104;
bss->ssid.security_policy = SECURITY_STATIC_WEP;
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
bss->wpa_pairwise = 0;
bss->rsn_pairwise = WPA_CIPHER_CCMP;
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
bss->wpa_pairwise = WPA_CIPHER_NONE;
bss->rsn_pairwise = WPA_CIPHER_NONE;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
}
}

View File

@ -15,6 +15,34 @@
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
/**
* mesh_conf - local MBSS state and settings
*/
struct mesh_conf {
u8 meshid[32];
u8 meshid_len;
/* Active Path Selection Protocol Identifier */
u8 mesh_pp_id;
/* Active Path Selection Metric Identifier */
u8 mesh_pm_id;
/* Congestion Control Mode Identifier */
u8 mesh_cc_id;
/* Synchronization Protocol Identifier */
u8 mesh_sp_id;
/* Authentication Protocol Identifier */
u8 mesh_auth_id;
u8 *ies;
int ie_len;
#define MESH_CONF_SEC_NONE BIT(0)
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
int dot11MeshHoldingTimeout; /* msec */
};
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094
@ -45,7 +73,8 @@ typedef enum hostap_security_policy {
SECURITY_STATIC_WEP = 1,
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4
SECURITY_WPA = 4,
SECURITY_OSEN = 5
} secpolicy;
struct hostapd_ssid {
@ -53,6 +82,8 @@ struct hostapd_ssid {
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
unsigned int wpa_psk_set:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@ -74,8 +105,6 @@ struct hostapd_ssid {
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct hostapd_wep_keys **dyn_vlan_keys;
size_t max_dyn_vlan_keys;
};
@ -107,6 +136,7 @@ struct hostapd_wpa_psk {
int group;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
};
struct hostapd_eap_user {
@ -124,7 +154,10 @@ struct hostapd_eap_user {
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
unsigned int remediation:1;
unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
struct hostapd_radius_attr *accept_attr;
};
struct hostapd_radius_attr {
@ -180,6 +213,7 @@ struct hostapd_nai_realm_data {
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@ -187,11 +221,10 @@ struct hostapd_bss_config {
unsigned int logger_syslog; /* module bitfield */
unsigned int logger_stdout; /* module bitfield */
char *dump_log_name; /* file name for state dump (SIGUSR1) */
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
int bss_load_update_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
@ -200,6 +233,7 @@ struct hostapd_bss_config {
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
@ -226,6 +260,8 @@ struct hostapd_bss_config {
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
@ -242,6 +278,7 @@ struct hostapd_bss_config {
int num_deny_mac;
int wds_sta;
int isolate;
int start_disabled;
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
@ -250,6 +287,7 @@ struct hostapd_bss_config {
int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
@ -294,7 +332,9 @@ struct hostapd_bss_config {
char *private_key;
char *private_key_passwd;
int check_crl;
char *ocsp_stapling_response;
char *dh_file;
char *openssl_ciphers;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@ -309,10 +349,9 @@ struct hostapd_bss_config {
char *radius_server_clients;
int radius_server_auth_port;
int radius_server_acct_port;
int radius_server_ipv6;
char *test_socket; /* UNIX domain socket path for driver_test */
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
* address instead of individual address
* (for driver_wired.c).
@ -324,7 +363,7 @@ struct hostapd_bss_config {
int wmm_enabled;
int wmm_uapsd;
struct hostapd_vlan *vlan, *vlan_tail;
struct hostapd_vlan *vlan;
macaddr bssid;
@ -340,6 +379,7 @@ struct hostapd_bss_config {
int wps_state;
#ifdef CONFIG_WPS
int wps_independent;
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
@ -356,6 +396,7 @@ struct hostapd_bss_config {
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
int force_per_enrollee_psk;
u8 *ap_settings;
size_t ap_settings_len;
char *upnp_iface;
@ -365,12 +406,14 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
struct wpabuf *wps_nfc_dh_privkey;
struct wpabuf *wps_nfc_dev_pw;
#endif /* CONFIG_WPS */
int pbc_in_m1;
char *server_id;
#define P2P_ENABLED BIT(0)
#define P2P_GROUP_OWNER BIT(1)
@ -378,6 +421,12 @@ struct hostapd_bss_config {
#define P2P_MANAGE BIT(3)
#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
int p2p;
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
u8 ip_addr_start[4];
u8 ip_addr_end[4];
#endif /* CONFIG_P2P */
int disassoc_low_ack;
int skip_inactivity_poll;
@ -436,9 +485,15 @@ struct hostapd_bss_config {
u16 gas_comeback_delay;
int gas_frag_limit;
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
int osen;
int proxy_arp;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
u16 anqp_domain_id;
unsigned int hs20_oper_friendly_name_count;
struct hostapd_lang_string *hs20_oper_friendly_name;
u8 *hs20_wan_metrics;
@ -446,6 +501,32 @@ struct hostapd_bss_config {
size_t hs20_connection_capability_len;
u8 *hs20_operating_class;
u8 hs20_operating_class_len;
struct hs20_icon {
u16 width;
u16 height;
char language[3];
char type[256];
char name[256];
char file[256];
} *hs20_icons;
size_t hs20_icons_count;
u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
size_t osu_ssid_len;
struct hs20_osu_provider {
unsigned int friendly_name_count;
struct hostapd_lang_string *friendly_name;
char *server_uri;
int *method_list;
char **icons;
size_t icons_count;
char *osu_nai;
unsigned int service_desc_count;
struct hostapd_lang_string *service_desc;
} *hs20_osu_providers, *last_osu;
size_t hs20_osu_providers_count;
unsigned int hs20_deauth_req_timeout;
char *subscr_remediation_url;
u8 subscr_remediation_method;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
@ -455,6 +536,23 @@ struct hostapd_bss_config {
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
unsigned int sae_anti_clogging_threshold;
int *sae_groups;
char *wowlan_triggers; /* Wake-on-WLAN triggers */
#ifdef CONFIG_TESTING_OPTIONS
u8 bss_load_test[5];
u8 bss_load_test_set;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
int mesh;
int radio_measurements;
int vendor_vht;
};
@ -462,7 +560,7 @@ struct hostapd_bss_config {
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
struct hostapd_bss_config *bss, *last_bss;
struct hostapd_bss_config **bss, *last_bss;
size_t num_bss;
u16 beacon_int;
@ -470,6 +568,7 @@ struct hostapd_config {
int fragm_threshold;
u8 send_probe_response;
u8 channel;
int *chanlist;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@ -480,6 +579,7 @@ struct hostapd_config {
int *basic_rates;
const struct wpa_driver_ops *driver;
char *driver_params;
int ap_table_max_size;
int ap_table_expiration_time;
@ -493,6 +593,18 @@ struct hostapd_config {
int ieee80211d;
int ieee80211h; /* DFS */
/*
* Local power constraint is an octet encoded as an unsigned integer in
* units of decibels. Invalid value -1 indicates that Power Constraint
* element will not be added.
*/
int local_pwr_constraint;
/* Control Spectrum Management bit */
int spectrum_mgmt_required;
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
@ -509,12 +621,34 @@ struct hostapd_config {
int ieee80211n;
int secondary_channel;
int require_ht;
int obss_interval;
u32 vht_capab;
int ieee80211ac;
int require_vht;
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
#ifdef CONFIG_P2P
u8 p2p_go_ctwindow;
#endif /* CONFIG_P2P */
#ifdef CONFIG_TESTING_OPTIONS
double ignore_probe_probability;
double ignore_auth_probability;
double ignore_assoc_probability;
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
#endif /* CONFIG_TESTING_OPTIONS */
#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 */
};
@ -522,18 +656,24 @@ int hostapd_mac_comp(const void *a, const void *b);
int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free_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,
const u8 *addr, int *vlan_id);
int hostapd_rate_found(int *list, int rate);
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
struct hostapd_wep_keys *b);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk);
const u8 *addr, const u8 *p2p_dev_addr,
const u8 *prev_psk);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
#endif /* HOSTAPD_CONFIG_H */

View File

@ -9,8 +9,8 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@ -129,14 +129,14 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
#ifdef CONFIG_WPS2
#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
struct wpabuf *a = wps_build_assoc_resp_ie();
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
wpabuf_put_buf(assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WPS2 */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
@ -171,8 +171,27 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
pos = hostapd_eid_osen(hapd, buf);
if (pos != buf) {
if (wpabuf_resize(&beacon, pos - buf) != 0)
goto fail;
wpabuf_put_data(beacon, buf, pos - buf);
if (wpabuf_resize(&proberesp, pos - buf) != 0)
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
size_t add = wpabuf_len(hapd->conf->vendor_elements);
if (wpabuf_resize(&beacon, add) == 0)
wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
if (wpabuf_resize(&proberesp, add) == 0)
wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
}
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
@ -262,7 +281,8 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
params.wpa = hapd->conf->wpa;
params.ieee802_1x = hapd->conf->ieee802_1x;
params.wpa_group = hapd->conf->wpa_group;
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_pairwise = hapd->conf->wpa_pairwise |
hapd->conf->rsn_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
#ifdef CONFIG_IEEE80211W
@ -278,7 +298,7 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
NULL, NULL, force_ifname, if_addr, NULL);
NULL, NULL, force_ifname, if_addr, NULL, 0);
}
@ -288,19 +308,19 @@ int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
}
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val)
int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
const u8 *addr, int aid, int val)
{
const char *bridge = NULL;
if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
return 0;
return -1;
if (hapd->conf->wds_bridge[0])
bridge = hapd->conf->wds_bridge;
else if (hapd->conf->bridge[0])
bridge = hapd->conf->bridge;
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
bridge);
bridge, ifname_wds);
}
@ -338,7 +358,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
u32 flags, u8 qosinfo)
const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo, u8 vht_opmode)
{
struct hostapd_sta_add_params params;
@ -355,6 +376,9 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, &params);
@ -407,20 +431,21 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge)
const char *bridge, int use_existing)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
bridge);
bridge, use_existing);
}
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->if_remove == NULL)
return -1;
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
@ -453,20 +478,25 @@ int hostapd_flush(struct hostapd_data *hapd)
}
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
int channel, int ht_enabled, int sec_channel_offset)
int hostapd_set_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)
{
struct hostapd_freq_params data;
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
vht_enabled, sec_channel_offset,
vht_oper_chwidth,
center_segment0, center_segment1,
hapd->iface->current_mode ?
hapd->iface->current_mode->vht_capab : 0))
return -1;
if (hapd->driver == NULL)
return 0;
if (hapd->driver->set_freq == NULL)
return 0;
os_memset(&data, 0, sizeof(data));
data.mode = mode;
data.freq = freq;
data.channel = channel;
data.ht_enabled = ht_enabled;
data.sec_channel_offset = sec_channel_offset;
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
@ -616,7 +646,7 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
const u8 *peer, u8 *buf, u16 *buf_len)
{
if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
return 0;
return -1;
return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
buf_len);
}
@ -632,3 +662,66 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
hapd->own_addr, hapd->own_addr, data,
len, 0);
}
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)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
int res;
if (!hapd->driver || !hapd->driver->start_dfs_cac)
return 0;
if (!iface->conf->ieee80211h) {
wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
"is not enabled");
return -1;
}
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
vht_enabled, sec_channel_offset,
vht_oper_chwidth, center_segment0,
center_segment1,
iface->current_mode->vht_capab)) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
}
return res;
}
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
const u8 *qos_map_set, u8 qos_map_set_len)
{
if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
}
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
os_memset(&params, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
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, &params);
}

View File

@ -1,6 +1,6 @@
/*
* hostapd - Driver operations
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -13,6 +13,8 @@ enum wpa_driver_if_type;
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct hostapd_freq_params;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@ -30,14 +32,15 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled);
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val);
int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
const u8 *addr, int aid, int val);
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
u32 flags, u8 qosinfo);
const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo, u8 vht_opmode);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@ -46,7 +49,7 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge);
const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@ -54,8 +57,10 @@ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
int channel, int ht_enabled, int sec_channel_offset);
int hostapd_set_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);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
@ -97,6 +102,12 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
int hostapd_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_drv_do_acs(struct hostapd_data *hapd);
#include "drivers/driver.h"
@ -105,6 +116,9 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
enum wnm_oper oper, const u8 *peer,
u8 *buf, u16 *buf_len);
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
@ -169,6 +183,14 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
static inline int hostapd_drv_set_acl(struct hostapd_data *hapd,
struct hostapd_acl_params *params)
{
if (hapd->driver == NULL || hapd->driver->set_acl == NULL)
return 0;
return hapd->driver->set_acl(hapd->drv_priv, params);
}
static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@ -213,4 +235,105 @@ static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
}
static inline int hostapd_drv_get_survey(struct hostapd_data *hapd,
unsigned int freq)
{
if (hapd->driver == NULL)
return -1;
if (!hapd->driver->get_survey)
return -1;
return hapd->driver->get_survey(hapd->drv_priv, freq);
}
static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
{
if (hapd->driver == NULL || hapd->driver->get_country == NULL)
return -1;
return hapd->driver->get_country(hapd->drv_priv, alpha2);
}
static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->get_radio_name == NULL)
return NULL;
return hapd->driver->get_radio_name(hapd->drv_priv);
}
static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings)
{
if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
return -ENOTSUP;
return hapd->driver->switch_channel(hapd->drv_priv, settings);
}
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
if (hapd->driver == NULL || hapd->driver->status == NULL)
return -1;
return hapd->driver->status(hapd->drv_priv, buf, buflen);
}
static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
int version, const u8 *ipaddr,
int prefixlen, const u8 *addr)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_add_ip_neigh == NULL)
return -1;
return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr,
prefixlen, addr);
}
static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd,
u8 version, const u8 *ipaddr)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_delete_ip_neigh == NULL)
return -1;
return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, version,
ipaddr);
}
static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd,
enum drv_br_port_attr attr,
unsigned int val)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_port_set_attr == NULL)
return -1;
return hapd->driver->br_port_set_attr(hapd->drv_priv, attr, val);
}
static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
enum drv_br_net_param param,
unsigned int val)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_set_net_param == NULL)
return -1;
return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
}
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
struct wpabuf *buf)
{
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
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 */

View File

@ -14,7 +14,6 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ieee802_11.h"
@ -33,7 +32,8 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
{
int i;
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
if (iface->current_mode == NULL ||
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
iface->conf->channel != ap->channel)
return 0;
@ -50,7 +50,7 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
}
struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
{
struct ap_info *s;
@ -87,34 +87,6 @@ static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
}
static void ap_ap_iter_list_add(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list) {
ap->iter_prev = iface->ap_iter_list->iter_prev;
iface->ap_iter_list->iter_prev = ap;
} else
ap->iter_prev = ap;
ap->iter_next = iface->ap_iter_list;
iface->ap_iter_list = ap;
}
static void ap_ap_iter_list_del(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list == ap)
iface->ap_iter_list = ap->iter_next;
else
ap->iter_prev->iter_next = ap->iter_next;
if (ap->iter_next)
ap->iter_next->iter_prev = ap->iter_prev;
else if (iface->ap_iter_list)
iface->ap_iter_list->iter_prev = ap->iter_prev;
}
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
@ -139,8 +111,8 @@ static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
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));
}
@ -148,7 +120,6 @@ static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
@ -171,25 +142,6 @@ static void hostapd_free_aps(struct hostapd_iface *iface)
}
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data)
{
struct ap_info *s;
int ret = 0;
s = iface->ap_list;
while (s) {
ret = func(s, data);
if (ret)
break;
s = s->next;
}
return ret;
}
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
{
struct ap_info *ap;
@ -203,7 +155,6 @@ static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
@ -221,9 +172,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
struct os_time now;
int new_ap = 0;
size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
@ -233,30 +182,17 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
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;
}
ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
if (elems->ssid) {
len = elems->ssid_len;
if (len >= sizeof(ap->ssid))
len = sizeof(ap->ssid) - 1;
os_memcpy(ap->ssid, elems->ssid, len);
ap->ssid[len] = '\0';
ap->ssid_len = len;
}
merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
ap->wpa = elems->wpa_ie != NULL;
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
@ -264,6 +200,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
else if (elems->ht_operation && elems->ht_operation_len >= 1)
ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@ -272,11 +210,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
else
ap->ht_support = 0;
ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
if (fi)
ap->datarate = fi->datarate;
os_get_reltime(&ap->last_beacon);
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@ -288,17 +222,23 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
"protection", MAC2STR(ap->addr));
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
" (channel %d) - enable protection",
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support) {
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
ap->channel == iface->conf->channel +
iface->conf->secondary_channel * 4)) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
" - enable protection", MAC2STR(ap->addr));
" (channel %d) - enable protection",
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
@ -311,7 +251,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
struct os_time now;
struct os_reltime now;
struct ap_info *ap;
int set_beacon = 0;
@ -320,12 +260,12 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
if (!iface->ap_list)
return;
os_get_time(&now);
os_get_reltime(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
now.sec)
if (!os_reltime_expired(&now, &ap->last_beacon,
iface->conf->ap_table_expiration_time))
break;
ap_free_ap(iface, ap);

View File

@ -14,42 +14,24 @@
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
* entries. iter_next/iter_prev are updated only when adding new BSSes
* and when removing old ones. These should be used when iterating
* through the table in a manner that allows beacons to be received
* during the iteration. */
* entries. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
struct ap_info *iter_next; /* next entry in AP iteration list */
struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
u16 beacon_int;
u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
u8 ssid[33];
size_t ssid_len;
int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int channel;
int datarate; /* in 100 kbps */
int ht_support;
unsigned int num_beacons; /* number of beacon frames received */
os_time_t last_beacon;
int already_seen; /* whether API call AP-NEW has already fetched
* information about this AP */
struct os_reltime last_beacon;
};
struct ieee802_11_elems;
struct hostapd_frame_info;
struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,

View File

@ -16,6 +16,7 @@
#include "wpa_auth.h"
#include "sta_info.h"
#include "ap_mlme.h"
#include "hostapd.h"
#ifndef CONFIG_NO_HOSTAPD_LOGGER
@ -80,7 +81,8 @@ void mlme_deauthenticate_indication(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
mlme_deletekeys_request(hapd, sta);
if (!hapd->iface->driver_ap_teardown)
mlme_deletekeys_request(hapd, sta);
}
@ -118,8 +120,6 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
* reassociation procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*
* sta->previous_ap contains the "Current AP" information from ReassocReq.
*/
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta)

View File

@ -79,7 +79,10 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
return 0;
}
@ -92,6 +95,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
@ -111,9 +115,17 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
#ifdef CONFIG_HS20
srv.subscr_remediation_url = conf->subscr_remediation_url;
srv.subscr_remediation_method = conf->subscr_remediation_method;
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@ -132,7 +144,7 @@ int authsrv_init(struct hostapd_data *hapd)
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
hapd->conf->dh_file)) {
hapd->conf->private_key || hapd->conf->dh_file)) {
struct tls_connection_params params;
hapd->ssl_ctx = tls_init(NULL);
@ -148,6 +160,9 @@ int authsrv_init(struct hostapd_data *hapd)
params.private_key = hapd->conf->private_key;
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
if (tls_global_set_params(hapd->ssl_ctx, &params)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");

View File

@ -4,14 +4,8 @@
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -21,7 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "common/hw_features_common.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@ -34,10 +28,56 @@
#include "ap_drv_ops.h"
#include "beacon.h"
#include "hs20.h"
#include "dfs.h"
#ifdef NEED_AP_MLME
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len)
{
if (!hapd->conf->radio_measurements || len < 2 + 4)
return eid;
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
*eid++ = 5;
*eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
*eid++ = 0x00;
*eid++ = 0x00;
*eid++ = 0x00;
*eid++ = 0x00;
return eid;
}
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
return eid;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->bss_load_test_set) {
*eid++ = WLAN_EID_BSS_LOAD;
*eid++ = 5;
os_memcpy(eid, hapd->conf->bss_load_test, 5);
eid += 5;
return eid;
}
#endif /* CONFIG_TESTING_OPTIONS */
if (hapd->conf->bss_load_update_period) {
*eid++ = WLAN_EID_BSS_LOAD;
*eid++ = 5;
WPA_PUT_LE16(eid, hapd->num_sta);
eid += 2;
*eid++ = hapd->iface->channel_utilization;
WPA_PUT_LE16(eid, 0); /* no available admission capabity */
eid += 2;
}
return eid;
}
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
@ -93,6 +133,74 @@ static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
}
static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
u8 local_pwr_constraint = 0;
int dfs;
if (hapd->iface->current_mode == NULL ||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return eid;
/* Let host drivers add this IE if DFS support is offloaded */
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return eid;
/*
* There is no DFS support and power constraint was not directly
* requested by config option.
*/
if (!hapd->iconf->ieee80211h &&
hapd->iconf->local_pwr_constraint == -1)
return eid;
/* Check if DFS is required by regulatory. */
dfs = hostapd_is_dfs_required(hapd->iface);
if (dfs < 0) {
wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d",
dfs);
dfs = 0;
}
if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1)
return eid;
/*
* ieee80211h (DFS) is enabled so Power Constraint element shall
* be added when running on DFS channel whenever local_pwr_constraint
* is configured or not. In order to meet regulations when TPC is not
* implemented using a transmit power that is below the legal maximum
* (including any mitigation factor) should help. In this case,
* indicate 3 dB below maximum allowed transmit power.
*/
if (hapd->iconf->local_pwr_constraint == -1)
local_pwr_constraint = 3;
/*
* A STA that is not an AP shall use a transmit power less than or
* equal to the local maximum transmit power level for the channel.
* The local maximum transmit power can be calculated from the formula:
* local max TX pwr = max TX pwr - local pwr constraint
* Where max TX pwr is maximum transmit power level specified for
* channel in Country element and local pwr constraint is specified
* for channel in this Power Constraint element.
*/
/* Element ID */
*pos++ = WLAN_EID_PWR_CONSTRAINT;
/* Length */
*pos++ = 1;
/* Local Power Constraint */
if (local_pwr_constraint)
*pos++ = local_pwr_constraint;
else
*pos++ = hapd->iconf->local_pwr_constraint;
return pos;
}
static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
@ -146,7 +254,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
continue; /* can use same entry */
}
if (start) {
if (start && prev) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
@ -187,6 +295,70 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
}
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
u8 chan;
if (!hapd->cs_freq_params.freq)
return eid;
if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
NUM_HOSTAPD_MODES)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
*eid++ = hapd->cs_block_tx;
*eid++ = chan;
*eid++ = hapd->cs_count;
return eid;
}
static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
{
u8 sec_ch;
if (!hapd->cs_freq_params.sec_channel_offset)
return eid;
if (hapd->cs_freq_params.sec_channel_offset == -1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
else if (hapd->cs_freq_params.sec_channel_offset == 1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
else
return eid;
*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
*eid++ = 1;
*eid++ = sec_ch;
return eid;
}
static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
u8 *start, unsigned int *csa_counter_off)
{
u8 *old_pos = pos;
if (!csa_counter_off)
return pos;
*csa_counter_off = 0;
pos = hostapd_eid_csa(hapd, pos);
if (pos != old_pos) {
/* save an offset to the counter - should be last byte */
*csa_counter_off = pos - start - 1;
pos = hostapd_eid_secondary_channel(hapd, pos);
}
return pos;
}
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
struct sta_info *sta,
const struct ieee80211_mgmt *req,
@ -208,6 +380,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#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;
@ -242,6 +418,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_country(hapd, pos, epos - pos);
/* Power Constraint element */
pos = hostapd_eid_pwr_constraint(hapd, pos);
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
@ -251,6 +430,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* RSN, MDIE, WPA */
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211N
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
@ -265,9 +448,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
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 */
@ -297,6 +486,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@ -390,6 +580,27 @@ void handle_probe_req(struct hostapd_data *hapd,
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 && elems.ds_params_len == 1 &&
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;
@ -443,12 +654,10 @@ void handle_probe_req(struct hostapd_data *hapd,
sta->ssid_probe = &hapd->conf->ssid;
} else {
if (!(mgmt->da[0] & 0x01)) {
char ssid_txt[33];
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
MAC2STR(mgmt->sa), ssid_txt,
MAC2STR(mgmt->sa),
wpa_ssid_txt(elems.ssid, elems.ssid_len),
MAC2STR(mgmt->da),
elems.ssid_list ? " (SSID list)" : "");
}
@ -456,7 +665,8 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#ifdef CONFIG_INTERWORKING
if (elems.interworking && elems.interworking_len >= 1) {
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
u8 ant = elems.interworking[0] & 0x0f;
if (ant != INTERWORKING_ANT_WILDCARD &&
ant != hapd->conf->access_network_type) {
@ -467,7 +677,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
}
if (elems.interworking &&
if (hapd->conf->interworking && elems.interworking &&
(elems.interworking_len == 7 || elems.interworking_len == 9)) {
const u8 *hessid;
if (elems.interworking_len == 7)
@ -485,9 +695,30 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
supp_rates_11b_only(&elems)) {
/* Indicates support for 11b rates only */
wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
MACSTR " with only 802.11b rates",
MAC2STR(mgmt->sa));
return;
}
#endif /* CONFIG_P2P */
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring probe request from " MACSTR,
MAC2STR(mgmt->sa));
return;
}
#endif /* CONFIG_TESTING_OPTIONS */
resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
@ -501,7 +732,7 @@ void handle_probe_req(struct hostapd_data *hapd,
is_broadcast_ether_addr(mgmt->da));
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
perror("handle_probe_req: send");
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
os_free(resp);
@ -549,23 +780,17 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
void ieee802_11_set_beacon(struct hostapd_data *hapd)
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
struct ieee80211_mgmt *head = NULL;
u8 *tail = NULL;
size_t head_len = 0, tail_len = 0;
u8 *resp = NULL;
size_t resp_len = 0;
struct wpa_driver_ap_params params;
struct wpabuf *beacon, *proberesp, *assocresp;
#ifdef NEED_AP_MLME
u16 capab_info;
u8 *pos, *tailpos;
#endif /* NEED_AP_MLME */
hapd->beacon_set_done = 1;
#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@ -581,12 +806,20 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
#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");
os_free(head);
os_free(tail);
return;
return -1;
}
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@ -631,6 +864,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
@ -641,6 +877,13 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
#ifdef CONFIG_IEEE80211N
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
@ -657,10 +900,15 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_interworking(hapd, tailpos);
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
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 */
@ -689,6 +937,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@ -702,94 +951,168 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */
os_memset(&params, 0, sizeof(params));
params.head = (u8 *) head;
params.head_len = head_len;
params.tail = tail;
params.tail_len = tail_len;
params.proberesp = resp;
params.proberesp_len = resp_len;
params.dtim_period = hapd->conf->dtim_period;
params.beacon_int = hapd->iconf->beacon_int;
params.basic_rates = hapd->iface->basic_rates;
params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
params.group_cipher = hapd->conf->wpa_group;
params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params.auth_algs = hapd->conf->auth_algs;
params.wpa_version = hapd->conf->wpa;
params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
os_memset(params, 0, sizeof(*params));
params->head = (u8 *) head;
params->head_len = head_len;
params->tail = tail;
params->tail_len = tail_len;
params->proberesp = resp;
params->proberesp_len = resp_len;
params->dtim_period = hapd->conf->dtim_period;
params->beacon_int = hapd->iconf->beacon_int;
params->basic_rates = hapd->iface->basic_rates;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
params->pairwise_ciphers = hapd->conf->wpa_pairwise |
hapd->conf->rsn_pairwise;
params->group_cipher = hapd->conf->wpa_group;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
params.hide_ssid = NO_SSID_HIDING;
params->hide_ssid = NO_SSID_HIDING;
break;
case 1:
params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
params->hide_ssid = HIDDEN_SSID_ZERO_LEN;
break;
case 2:
params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
break;
}
hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
params.beacon_ies = beacon;
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.isolate = hapd->conf->isolate;
params->isolate = hapd->conf->isolate;
params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params.cts_protect = !!(ieee802_11_erp_info(hapd) &
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
params->preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE;
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
params.short_slot_time =
params->short_slot_time =
hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
else
params.short_slot_time = -1;
params->short_slot_time = -1;
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
params.ht_opmode = -1;
params->ht_opmode = -1;
else
params.ht_opmode = hapd->iface->ht_op_mode;
params->ht_opmode = hapd->iface->ht_op_mode;
#endif /* NEED_AP_MLME */
params.interworking = hapd->conf->interworking;
params->interworking = hapd->conf->interworking;
if (hapd->conf->interworking &&
!is_zero_ether_addr(hapd->conf->hessid))
params.hessid = hapd->conf->hessid;
params.access_network_type = hapd->conf->access_network_type;
params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
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;
params->disable_dgaf = hapd->conf->disable_dgaf;
if (hapd->conf->osen) {
params->privacy = 1;
params->osen = 1;
}
#endif /* CONFIG_HS20 */
if (hostapd_drv_set_ap(hapd, &params))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
os_free(tail);
os_free(head);
os_free(resp);
return 0;
}
void ieee802_11_set_beacons(struct hostapd_iface *iface)
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
{
os_free(params->tail);
params->tail = NULL;
os_free(params->head);
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
}
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct wpa_driver_ap_params params;
struct hostapd_freq_params freq;
struct hostapd_iface *iface = hapd->iface;
struct hostapd_config *iconf = iface->conf;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
return -1;
}
hapd->beacon_set_done = 1;
if (ieee802_11_build_ap_params(hapd, &params) < 0)
return -1;
if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
0)
goto fail;
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,
iconf->channel, iconf->ieee80211n,
iconf->ieee80211ac,
iconf->secondary_channel,
iconf->vht_oper_chwidth,
iconf->vht_oper_centr_freq_seg0_idx,
iconf->vht_oper_centr_freq_seg1_idx,
iface->current_mode->vht_capab) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, &params);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
if (res)
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
else
ret = 0;
fail:
ieee802_11_free_ap_params(&params);
return ret;
}
int ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_set_beacon(iface->bss[i]);
int ret = 0;
for (i = 0; i < iface->num_bss; i++) {
if (iface->bss[i]->started &&
ieee802_11_set_beacon(iface->bss[i]) < 0)
ret = -1;
}
return ret;
}
/* only update beacons if started */
void ieee802_11_update_beacons(struct hostapd_iface *iface)
int ieee802_11_update_beacons(struct hostapd_iface *iface)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
if (iface->bss[i]->beacon_set_done)
ieee802_11_set_beacon(iface->bss[i]);
int ret = 0;
for (i = 0; i < iface->num_bss; i++) {
if (iface->bss[i]->beacon_set_done && iface->bss[i]->started &&
ieee802_11_set_beacon(iface->bss[i]) < 0)
ret = -1;
}
return ret;
}
#endif /* CONFIG_NATIVE_WINDOWS */

View File

@ -3,14 +3,8 @@
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef BEACON_H
@ -21,8 +15,11 @@ struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal);
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
void ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_set_beacon(struct hostapd_data *hapd);
int ieee802_11_set_beacons(struct hostapd_iface *iface);
int ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
#endif /* BEACON_H */

View File

@ -0,0 +1,65 @@
/*
* BSS Load Element / Channel Utilization
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "hostapd.h"
#include "bss_load.h"
#include "ap_drv_ops.h"
#include "beacon.h"
static void update_channel_utilization(void *eloop_data, void *user_data)
{
struct hostapd_data *hapd = eloop_data;
unsigned int sec, usec;
int err;
if (!(hapd->beacon_set_done && hapd->started))
return;
err = hostapd_drv_get_survey(hapd, hapd->iface->freq);
if (err) {
wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data");
return;
}
ieee802_11_set_beacon(hapd);
sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
usec = (hapd->bss_load_update_timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
}
int bss_load_update_init(struct hostapd_data *hapd)
{
struct hostapd_bss_config *conf = hapd->conf;
struct hostapd_config *iconf = hapd->iconf;
unsigned int sec, usec;
if (!conf->bss_load_update_period || !iconf->beacon_int)
return -1;
hapd->bss_load_update_timeout = conf->bss_load_update_period *
iconf->beacon_int;
sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
usec = (hapd->bss_load_update_timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
return 0;
}
void bss_load_update_deinit(struct hostapd_data *hapd)
{
eloop_cancel_timeout(update_channel_utilization, hapd, NULL);
}

View File

@ -0,0 +1,17 @@
/*
* BSS load update
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef BSS_LOAD_UPDATE_H
#define BSS_LOAD_UPDATE_H
int bss_load_update_init(struct hostapd_data *hapd);
void bss_load_update_deinit(struct hostapd_data *hapd);
#endif /* BSS_LOAD_UPDATE_H */

View File

@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2014, 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,8 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@ -21,25 +23,61 @@
#include "ap_drv_ops.h"
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
struct hostap_sta_driver_data data;
int ret;
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
return 0;
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
"rx_bytes=%lu\ntx_bytes=%lu\n",
data.rx_packets, data.tx_packets,
data.rx_bytes, data.tx_bytes);
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
static int hostapd_get_sta_conn_time(struct sta_info *sta,
char *buf, size_t buflen)
{
struct os_time now, age;
int len = 0, ret;
struct os_reltime age;
int ret;
if (!sta->connected_time.sec)
return 0;
os_get_time(&now);
os_time_sub(&now, &sta->connected_time, &age);
os_reltime_age(&sta->connected_time, &age);
ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
ret = os_snprintf(buf, buflen, "connected_time=%u\n",
(unsigned int) age.sec);
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
len += ret;
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
return len;
static const char * timeout_next_str(int val)
{
switch (val) {
case STA_NULLFUNC:
return "NULLFUNC POLL";
case STA_DISASSOC:
return "DISASSOC";
case STA_DEAUTH:
return "DEAUTH";
case STA_REMOVE:
return "REMOVE";
case STA_DISASSOC_FROM_CLI:
return "DISASSOC_FROM_CLI";
}
return "?";
}
@ -47,19 +85,42 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
int len, res, ret;
int len, res, ret, i;
if (sta == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
if (!sta)
return 0;
len = 0;
ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
MAC2STR(sta->addr));
if (ret < 0 || (size_t) ret >= buflen - len)
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
if (ret < 0)
return len;
len += ret;
ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
"listen_interval=%d\nsupported_rates=",
sta->aid, sta->capability, sta->listen_interval);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
for (i = 0; i < sta->supported_rates_len; i++) {
ret = os_snprintf(buf + len, buflen - len, "%02x%s",
sta->supported_rates[i],
i + 1 < sta->supported_rates_len ? " " : "");
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
timeout_next_str(sta->timeout_next));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@ -80,9 +141,17 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (res >= 0)
len += res;
res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
if (res >= 0)
len += res;
len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
#ifdef CONFIG_SAE
if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
sta->sae->group);
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_SAE */
return len;
}
@ -100,15 +169,37 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
{
u8 addr[ETH_ALEN];
int ret;
const char *pos;
struct sta_info *sta;
if (hwaddr_aton(txtaddr, addr)) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
buf, buflen);
sta = ap_get_sta(hapd, addr);
if (sta == NULL)
return -1;
pos = os_strchr(txtaddr, ' ');
if (pos) {
pos++;
#ifdef HOSTAPD_DUMP_STATE
if (os_strcmp(pos, "eapol") == 0) {
if (sta->eapol_sm == NULL)
return -1;
return eapol_auth_dump_state(sta->eapol_sm, buf,
buflen);
}
#endif /* HOSTAPD_DUMP_STATE */
return -1;
}
return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
}
@ -122,10 +213,14 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
if (hwaddr_aton(txtaddr, addr) ||
(sta = ap_get_sta(hapd, addr)) == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
}
if (!sta->next)
return 0;
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
@ -145,11 +240,12 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
if (mgmt == NULL)
return -1;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u)",
MAC2STR(addr), minor_reason_code, stype);
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u (%s))",
MAC2STR(addr), minor_reason_code, stype,
fc2str(mgmt->frame_control));
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
@ -165,9 +261,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + 3 + 1;
WPA_PUT_BE24(pos, OUI_WFA);
pos += 3;
*pos++ = P2P_OUI_TYPE;
WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
pos += 4;
*pos++ = P2P_ATTR_MINOR_REASON_CODE;
WPA_PUT_LE16(pos, 1);
@ -189,6 +284,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
txtaddr);
@ -196,6 +292,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (hwaddr_aton(txtaddr, addr))
return -1;
pos = os_strstr(txtaddr, " reason=");
if (pos)
reason = atoi(pos + 8);
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
@ -210,8 +310,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
mgmt.u.deauth.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
@ -228,11 +327,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
@ -246,6 +344,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
txtaddr);
@ -253,6 +352,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (hwaddr_aton(txtaddr, addr))
return -1;
pos = os_strstr(txtaddr, " reason=");
if (pos)
reason = atoi(pos + 8);
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
@ -267,8 +370,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
@ -285,13 +387,159 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
return 0;
}
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
struct hostapd_iface *iface = hapd->iface;
int len = 0, ret;
size_t i;
ret = os_snprintf(buf + len, buflen - len,
"state=%s\n"
"phy=%s\n"
"freq=%d\n"
"num_sta_non_erp=%d\n"
"num_sta_no_short_slot_time=%d\n"
"num_sta_no_short_preamble=%d\n"
"olbc=%d\n"
"num_sta_ht_no_gf=%d\n"
"num_sta_no_ht=%d\n"
"num_sta_ht_20_mhz=%d\n"
"num_sta_ht40_intolerant=%d\n"
"olbc_ht=%d\n"
"ht_op_mode=0x%x\n",
hostapd_state_text(iface->state),
iface->phy,
iface->freq,
iface->num_sta_non_erp,
iface->num_sta_no_short_slot_time,
iface->num_sta_no_short_preamble,
iface->olbc,
iface->num_sta_ht_no_gf,
iface->num_sta_no_ht,
iface->num_sta_ht_20mhz,
iface->num_sta_ht40_intolerant,
iface->olbc_ht,
iface->ht_op_mode);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
if (!iface->cac_started || !iface->dfs_cac_ms) {
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%d\n"
"cac_time_left_seconds=N/A\n",
iface->dfs_cac_ms / 1000);
} else {
/* CAC started and CAC time set - calculate remaining time */
struct os_reltime now;
unsigned int left_time;
os_reltime_age(&iface->dfs_cac_start, &now);
left_time = iface->dfs_cac_ms / 1000 - now.sec;
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%u\n"
"cac_time_left_seconds=%u\n",
iface->dfs_cac_ms / 1000,
left_time);
}
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"vht_oper_chwidth=%d\n"
"vht_oper_centr_freq_seg0_idx=%d\n"
"vht_oper_centr_freq_seg1_idx=%d\n",
iface->conf->channel,
iface->conf->secondary_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->vht_oper_chwidth,
iface->conf->vht_oper_centr_freq_seg0_idx,
iface->conf->vht_oper_centr_freq_seg1_idx);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
ret = os_snprintf(buf + len, buflen - len,
"bss[%d]=%s\n"
"bssid[%d]=" MACSTR "\n"
"ssid[%d]=%s\n"
"num_sta[%d]=%d\n",
(int) i, bss->conf->iface,
(int) i, MAC2STR(bss->own_addr),
(int) i,
wpa_ssid_txt(bss->conf->ssid.ssid,
bss->conf->ssid.ssid_len),
(int) i, bss->num_sta);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
return len;
}
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings)
{
char *end;
os_memset(settings, 0, sizeof(*settings));
settings->cs_count = strtol(pos, &end, 10);
if (pos == end) {
wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
return -1;
}
settings->freq_params.freq = atoi(end);
if (settings->freq_params.freq == 0) {
wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
return -1;
}
#define SET_CSA_SETTING(str) \
do { \
const char *pos2 = os_strstr(pos, " " #str "="); \
if (pos2) { \
pos2 += sizeof(" " #str "=") - 1; \
settings->freq_params.str = atoi(pos2); \
} \
} while (0)
SET_CSA_SETTING(center_freq1);
SET_CSA_SETTING(center_freq2);
SET_CSA_SETTING(bandwidth);
SET_CSA_SETTING(sec_channel_offset);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
return 0;
}
int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
{
return hostapd_drv_stop_ap(hapd);
}

View File

@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -19,5 +19,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
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 */

1064
contrib/wpa/src/ap/dfs.c Normal file

File diff suppressed because it is too large Load Diff

30
contrib/wpa/src/ap/dfs.h Normal file
View File

@ -0,0 +1,30 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DFS_H
#define DFS_H
int hostapd_handle_dfs(struct hostapd_iface *iface);
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
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 */

View File

@ -0,0 +1,178 @@
/*
* DHCP snooping for Proxy ARP
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <netinet/ip.h>
#include <netinet/udp.h>
#include "utils/common.h"
#include "l2_packet/l2_packet.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_drv_ops.h"
#include "x_snoop.h"
#include "dhcp_snoop.h"
struct bootp_pkt {
struct iphdr iph;
struct udphdr udph;
u8 op;
u8 htype;
u8 hlen;
u8 hops;
be32 xid;
be16 secs;
be16 flags;
be32 client_ip;
be32 your_ip;
be32 server_ip;
be32 relay_ip;
u8 hw_addr[16];
u8 serv_name[64];
u8 boot_file[128];
u8 exten[312];
} STRUCT_PACKED;
#define DHCPACK 5
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)
{
struct hostapd_data *hapd = ctx;
const struct bootp_pkt *b;
struct sta_info *sta;
int exten_len;
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
u16 tot_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
tot_len = ntohs(b->iph.tot_len);
if (tot_len > (unsigned int) (len - ETH_HLEN))
return;
if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
return;
/* Parse DHCP options */
end = (const u8 *) b + tot_len;
pos = &b->exten[4];
while (pos < end && *pos != 0xff) {
const u8 *opt = pos++;
if (*opt == 0) /* padding */
continue;
pos += *pos + 1;
if (pos >= end)
break;
switch (*opt) {
case 1: /* subnet mask */
if (opt[1] == 4)
subnet_mask = WPA_GET_BE32(&opt[2]);
if (subnet_mask == 0)
return;
while (!(subnet_mask & 0x1)) {
subnet_mask >>= 1;
prefixlen--;
}
break;
case 53: /* message type */
if (opt[1])
msgtype = opt[2];
break;
default:
break;
}
}
if (msgtype == DHCPACK) {
if (b->your_ip == 0)
return;
/* DHCPACK for DHCPREQUEST */
sta = ap_get_sta(hapd, b->hw_addr);
if (!sta)
return;
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
" @ 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 %s from the ip neigh table",
ipaddr_str(be_to_host32(sta->ipaddr)));
hostapd_drv_br_delete_ip_neigh(hapd, 4,
(u8 *) &sta->ipaddr);
}
res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
prefixlen, sta->addr);
if (res) {
wpa_printf(MSG_DEBUG,
"dhcp_snoop: Adding ip neigh table failed: %d",
res);
return;
}
sta->ipaddr = b->your_ip;
}
if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
continue;
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
(u8 *) buf, len);
}
}
}
int dhcp_snoop_init(struct hostapd_data *hapd)
{
hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp,
L2_PACKET_FILTER_DHCP);
if (hapd->sock_dhcp == NULL) {
wpa_printf(MSG_DEBUG,
"dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s",
strerror(errno));
return -1;
}
return 0;
}
void dhcp_snoop_deinit(struct hostapd_data *hapd)
{
l2_packet_deinit(hapd->sock_dhcp);
}

View File

@ -0,0 +1,30 @@
/*
* DHCP snooping for Proxy ARP
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DHCP_SNOOP_H
#define DHCP_SNOOP_H
#ifdef CONFIG_PROXYARP
int dhcp_snoop_init(struct hostapd_data *hapd);
void dhcp_snoop_deinit(struct hostapd_data *hapd);
#else /* CONFIG_PROXYARP */
static inline int dhcp_snoop_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void dhcp_snoop_deinit(struct hostapd_data *hapd)
{
}
#endif /* CONFIG_PROXYARP */
#endif /* DHCP_SNOOP_H */

View File

@ -1,6 +1,6 @@
/*
* hostapd / Callback functions for driver wrappers
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -9,10 +9,12 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "radius/radius.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@ -28,6 +30,8 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
#include "dfs.h"
#include "beacon.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@ -44,6 +48,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#endif /* CONFIG_IEEE80211R */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
/*
@ -75,6 +80,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ie = elems.wpa_ie - 2;
ielen = elems.wpa_ie_len + 2;
wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
#ifdef CONFIG_HS20
} else if (elems.osen) {
ie = elems.osen - 2;
ielen = elems.osen_len + 2;
wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
#endif /* CONFIG_HS20 */
} else {
ie = NULL;
ielen = 0;
@ -84,6 +95,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta = ap_get_sta(hapd, addr);
if (sta) {
ap_sta_no_session_timeout(hapd, sta);
accounting_sta_stop(hapd, sta);
/*
@ -106,9 +118,36 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
wpabuf_free(sta->p2p_ie);
sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
P2P_IE_VENDOR_TYPE);
if (sta->p2p_ie)
p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
}
#endif /* CONFIG_P2P */
#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 =
(struct ieee80211_ht_capabilities *)
elems.ht_capabilities;
if (le_to_host16(ht_cap->ht_capabilities_info) &
HT_CAP_INFO_40MHZ_INTOLERANT)
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
if (elems.ext_capab[4] & 0x01)
sta->qos_map_enabled = 1;
}
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
@ -154,7 +193,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr);
sta->addr,
p2p_dev_addr);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
"machine");
@ -267,6 +307,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MAYBE_WPS;
wpabuf_free(wps);
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (elems.osen == NULL) {
hostapd_logger(
hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"No HS 2.0 OSEN element in association request");
return WLAN_STATUS_INVALID_IE;
}
wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_WARNING, "Failed to initialize WPA "
"state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
elems.osen - 2, elems.osen_len + 2) < 0)
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
#ifdef CONFIG_WPS
skip_wpa_check:
@ -277,6 +340,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->auth_alg, req_ies, req_ies_len);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
if (sta->auth_alg == WLAN_AUTH_FT)
ap_sta_set_authorized(hapd, sta, 1);
#else /* CONFIG_IEEE80211R */
/* Keep compiler silent about unused variables */
if (status) {
@ -285,6 +351,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
hostapd_set_sta_flags(hapd, sta);
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
@ -367,14 +436,16 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset)
int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
int channel;
int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
"freq=%d, ht=%d, offset=%d", freq, ht, offset);
HOSTAPD_LEVEL_INFO,
"driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
freq, ht, offset, width, channel_width_to_string(width),
cf1, cf2);
hapd->iface->freq = freq;
@ -386,13 +457,124 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
return;
}
switch (width) {
case CHAN_WIDTH_80:
chwidth = VHT_CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
chwidth = VHT_CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
chwidth = VHT_CHANWIDTH_160MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
default:
chwidth = VHT_CHANWIDTH_USE_HT;
break;
}
switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
if (cf1 > 5000)
seg0_idx = (cf1 - 5000) / 5;
if (cf2 > 5000)
seg1_idx = (cf2 - 5000) / 5;
break;
default:
seg0_idx = hostapd_hw_get_channel(hapd, cf1);
seg1_idx = hostapd_hw_get_channel(hapd, cf2);
break;
}
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
if (!ht)
hapd->iconf->ieee80211ac = 0;
hapd->iconf->secondary_channel = offset;
hapd->iconf->vht_oper_chwidth = chwidth;
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 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 */
}
void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
const u8 *addr, int reason_code)
{
switch (reason_code) {
case MAX_CLIENT_REACHED:
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
MAC2STR(addr));
break;
case BLOCKED_CLIENT:
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
MAC2STR(addr));
break;
}
}
#ifdef CONFIG_ACS
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
u8 pri_channel, u8 sec_channel)
{
int channel;
int ret;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
hapd->iconf->channel);
return;
}
hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
channel = pri_channel;
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
return;
}
hapd->iconf->channel = channel;
if (sec_channel == 0)
hapd->iconf->secondary_channel = 0;
else if (sec_channel < pri_channel)
hapd->iconf->secondary_channel = -1;
else if (sec_channel > pri_channel)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
return;
}
ret = hostapd_acs_completed(hapd->iface, 0);
if (ret) {
wpa_printf(MSG_ERROR,
"ACS: Possibly channel configuration is invalid");
}
}
#endif /* CONFIG_ACS */
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal)
@ -452,7 +634,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
if (!sta) {
sta = ap_sta_add(hapd, rx_auth->peer);
if (sta == NULL) {
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
}
@ -463,7 +645,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr);
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
"state machine");
@ -484,39 +666,48 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
static void hostapd_action_rx(struct hostapd_data *hapd,
struct rx_action *action)
struct rx_mgmt *drv_mgmt)
{
struct ieee80211_mgmt *mgmt;
struct sta_info *sta;
size_t plen __maybe_unused;
u16 fc;
if (drv_mgmt->frame_len < 24 + 1)
return;
plen = drv_mgmt->frame_len - 24 - 1;
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
action->category, (int) action->len);
mgmt->u.action.category, (int) plen);
sta = ap_get_sta(hapd, action->sa);
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return;
}
#ifdef CONFIG_IEEE80211R
if (action->category == WLAN_ACTION_FT) {
wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
__func__, (int) action->len);
wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
if (mgmt->u.action.category == WLAN_ACTION_FT) {
const u8 *payload = drv_mgmt->frame + 24 + 1;
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
__func__, (int) action->len);
ieee802_11_sa_query_action(hapd, action->sa,
*(action->data + 1),
action->data + 2);
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
ieee802_11_sa_query_action(
hapd, mgmt->sa,
mgmt->u.action.u.sa_query_resp.action,
mgmt->u.action.u.sa_query_resp.trans_id);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (action->category == WLAN_ACTION_WNM) {
wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
__func__, (int) action->len);
ieee802_11_rx_wnm_action_ap(hapd, action);
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
}
#endif /* CONFIG_WNM */
}
@ -558,17 +749,32 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
}
static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
{
struct hostapd_iface *iface = hapd->iface;
const struct ieee80211_hdr *hdr;
const u8 *bssid;
struct hostapd_frame_info fi;
int ret;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->ext_mgmt_frame_handling) {
size_t hex_len = 2 * rx_mgmt->frame_len + 1;
char *hex = os_malloc(hex_len);
if (hex) {
wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
rx_mgmt->frame_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
os_free(hex);
}
return 1;
}
#endif /* CONFIG_TESTING_OPTIONS */
hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
if (bssid == NULL)
return;
return 0;
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
@ -583,7 +789,7 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
hapd = iface->bss[0];
else
return;
return 0;
}
os_memset(&fi, 0, sizeof(fi));
@ -592,53 +798,25 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd == HAPD_BROADCAST) {
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
rx_mgmt->frame_len, &fi);
ret = 0;
for (i = 0; i < iface->num_bss; i++) {
/* if bss is set, driver will call this function for
* each bss individually. */
if (rx_mgmt->drv_priv &&
(iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
continue;
if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
rx_mgmt->frame_len, &fi) > 0)
ret = 1;
}
} else
ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
&fi);
random_add_randomness(&fi, sizeof(fi));
}
static void hostapd_rx_action(struct hostapd_data *hapd,
struct rx_action *rx_action)
{
struct rx_mgmt rx_mgmt;
u8 *buf;
struct ieee80211_hdr *hdr;
wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
" BSSID=" MACSTR " category=%u",
MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
MAC2STR(rx_action->bssid), rx_action->category);
wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
rx_action->data, rx_action->len);
buf = os_zalloc(24 + 1 + rx_action->len);
if (buf == NULL)
return;
hdr = (struct ieee80211_hdr *) buf;
hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
if (rx_action->category == WLAN_ACTION_SA_QUERY) {
/*
* Assume frame was protected; it would have been dropped if
* not.
*/
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
}
os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
buf[24] = rx_action->category;
os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
rx_mgmt.frame = buf;
rx_mgmt.frame_len = 24 + 1 + rx_action->len;
hostapd_mgmt_rx(hapd, &rx_mgmt);
os_free(buf);
return ret;
}
@ -697,6 +875,181 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
}
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (!chan)
return NULL;
if ((unsigned int) chan->freq == freq)
return chan;
}
return NULL;
}
static void hostapd_update_nf(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
struct freq_survey *survey)
{
if (!iface->chans_surveyed) {
chan->min_nf = survey->nf;
iface->lowest_nf = survey->nf;
} else {
if (dl_list_empty(&chan->survey_list))
chan->min_nf = survey->nf;
else if (survey->nf < chan->min_nf)
chan->min_nf = survey->nf;
if (survey->nf < iface->lowest_nf)
iface->lowest_nf = survey->nf;
}
}
static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_res)
{
struct hostapd_channel_data *chan;
struct freq_survey *survey;
u64 divisor, dividend;
survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
list);
if (!survey || !survey->freq)
return;
chan = hostapd_get_mode_channel(iface, survey->freq);
if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
return;
wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
survey->freq,
(unsigned long int) survey->channel_time,
(unsigned long int) survey->channel_time_busy);
if (survey->channel_time > iface->last_channel_time &&
survey->channel_time > survey->channel_time_busy) {
dividend = survey->channel_time_busy -
iface->last_channel_time_busy;
divisor = survey->channel_time - iface->last_channel_time;
iface->channel_utilization = dividend * 255 / divisor;
wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
iface->channel_utilization);
}
iface->last_channel_time = survey->channel_time;
iface->last_channel_time_busy = survey->channel_time_busy;
}
static void hostapd_event_get_survey(struct hostapd_data *hapd,
struct survey_results *survey_results)
{
struct hostapd_iface *iface = hapd->iface;
struct freq_survey *survey, *tmp;
struct hostapd_channel_data *chan;
if (dl_list_empty(&survey_results->survey_list)) {
wpa_printf(MSG_DEBUG, "No survey data received");
return;
}
if (survey_results->freq_filter) {
hostapd_single_channel_get_survey(iface, survey_results);
return;
}
dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
struct freq_survey, list) {
chan = hostapd_get_mode_channel(iface, survey->freq);
if (!chan)
continue;
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
dl_list_del(&survey->list);
dl_list_add_tail(&chan->survey_list, &survey->list);
hostapd_update_nf(iface, chan, survey);
iface->chans_surveyed++;
}
}
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
hapd->conf->iface);
if (hapd->csa_in_progress) {
wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
hapd->conf->iface);
hostapd_switch_channel_fallback(hapd->iface,
&hapd->cs_freq_params);
}
}
static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
radar->cf1, radar->cf2);
}
static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
struct dfs_event *radar)
{
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
radar->chan_offset, radar->chan_width,
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 */
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@ -713,6 +1066,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
level = MSG_EXCESSIVE;
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
level = MSG_EXCESSIVE;
}
wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
@ -727,12 +1083,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (hapd->iface->scan_cb)
hapd->iface->scan_cb(hapd->iface);
break;
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RRB_RX:
wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
break;
#endif /* CONFIG_IEEE80211R */
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd, NULL);
break;
@ -767,10 +1117,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
case EVENT_RX_MGMT:
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
break;
#endif /* NEED_AP_MLME */
case EVENT_RX_MGMT:
if (!data->rx_mgmt.frame)
break;
#ifdef NEED_AP_MLME
if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
break;
#endif /* NEED_AP_MLME */
hostapd_action_rx(hapd, &data->rx_mgmt);
break;
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
@ -791,6 +1147,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->eapol_rx.data_len);
break;
case EVENT_ASSOC:
if (!data)
return;
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len,
@ -809,15 +1167,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
case EVENT_RX_ACTION:
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
data->rx_action.bssid == NULL)
break;
#ifdef NEED_AP_MLME
hostapd_rx_action(hapd, &data->rx_action);
#endif /* NEED_AP_MLME */
hostapd_action_rx(hapd, &data->rx_action);
break;
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
@ -826,8 +1175,84 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
data->ch_switch.ch_offset,
data->ch_switch.ch_width,
data->ch_switch.cf1,
data->ch_switch.cf2);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)
break;
hostapd_event_connect_failed_reason(
hapd, data->connect_failed_reason.addr,
data->connect_failed_reason.code);
break;
case EVENT_SURVEY:
hostapd_event_get_survey(hapd, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
hostapd_event_iface_unavailable(hapd);
break;
case EVENT_DFS_RADAR_DETECTED:
if (!data)
break;
hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
break;
case EVENT_DFS_CAC_FINISHED:
if (!data)
break;
hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
break;
case EVENT_DFS_CAC_ABORTED:
if (!data)
break;
hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
break;
case EVENT_DFS_NOP_FINISHED:
if (!data)
break;
hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
break;
case EVENT_CHANNEL_LIST_CHANGED:
/* channel list changed (regulatory?), update channel list */
/* TODO: check this. hostapd_get_hw_features() initializes
* too much stuff. */
/* hostapd_get_hw_features(hapd->iface); */
hostapd_channel_list_updated(
hapd->iface, data->channel_list_changed.initiator);
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);
break;
#endif /* CONFIG_ACS */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;

View File

@ -83,12 +83,14 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "password") == 0 && argv[i]) {
os_free(user->password);
bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[i]);
user->password = (u8 *) os_strdup(argv[i]);
user->next = (void *) 1;
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
set_user_methods(user, argv[i]);
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
user->remediation = strlen(argv[i]) > 0;
}
}
@ -116,7 +118,7 @@ static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
if (len <= user->identity_len &&
os_memcmp(argv[id], user->identity, len) == 0 &&
(user->password == NULL || len > user->password_len)) {
os_free(user->password);
bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[id]);
user->password = (u8 *) os_strdup(argv[id]);
user->next = (void *) 1;
@ -156,8 +158,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
return NULL;
}
os_free(hapd->tmp_eap_user.identity);
os_free(hapd->tmp_eap_user.password);
bin_clear_free(hapd->tmp_eap_user.identity,
hapd->tmp_eap_user.identity_len);
bin_clear_free(hapd->tmp_eap_user.password,
hapd->tmp_eap_user.password_len);
os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
hapd->tmp_eap_user.phase2 = phase2;
hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
@ -173,8 +177,8 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
}
os_snprintf(cmd, sizeof(cmd),
"SELECT password,methods FROM users WHERE "
"identity='%s' AND phase2=%d;", id_str, phase2);
"SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
id_str, phase2);
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {

View File

@ -1,6 +1,6 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -19,6 +19,13 @@
#include "gas_serv.h"
static void convert_to_protected_dual(struct wpabuf *msg)
{
u8 *categ = wpabuf_mhead_u8(msg);
*categ = WLAN_ACTION_PROTECTED_DUAL;
}
static struct gas_dialog_info *
gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
{
@ -46,10 +53,12 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
* it to be that long.
*/
ap_sta_session_timeout(hapd, sta, 5);
} else {
ap_sta_replenish_timeout(hapd, sta, 5);
}
if (sta->gas_dialog == NULL) {
sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
sizeof(struct gas_dialog_info));
if (sta->gas_dialog == NULL)
return NULL;
@ -62,7 +71,6 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
continue;
dia = &sta->gas_dialog[i];
dia->valid = 1;
dia->index = i;
dia->dialog_token = dialog_token;
sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
return dia;
@ -150,6 +158,10 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
if (hapd->conf->hs20_operating_class)
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
if (hapd->conf->hs20_osu_providers_count)
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
if (hapd->conf->hs20_icons_count)
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
@ -402,7 +414,7 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
gas_anqp_set_element_len(buf, realm_data_len);
}
gas_anqp_set_element_len(buf, len);
} else if (nai_home_realm && hapd->conf->nai_realm_data) {
} else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
home_realm_len);
}
@ -505,18 +517,188 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
}
}
static void anqp_add_osu_provider(struct wpabuf *buf,
struct hostapd_bss_config *bss,
struct hs20_osu_provider *p)
{
u8 *len, *len2, *count;
unsigned int i;
len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
/* OSU Friendly Name Duples */
len2 = wpabuf_put(buf, 2);
for (i = 0; i < p->friendly_name_count; i++) {
struct hostapd_lang_string *s = &p->friendly_name[i];
wpabuf_put_u8(buf, 3 + s->name_len);
wpabuf_put_data(buf, s->lang, 3);
wpabuf_put_data(buf, s->name, s->name_len);
}
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
/* OSU Server URI */
if (p->server_uri) {
wpabuf_put_u8(buf, os_strlen(p->server_uri));
wpabuf_put_str(buf, p->server_uri);
} else
wpabuf_put_u8(buf, 0);
/* OSU Method List */
count = wpabuf_put(buf, 1);
for (i = 0; p->method_list[i] >= 0; i++)
wpabuf_put_u8(buf, p->method_list[i]);
*count = i;
/* Icons Available */
len2 = wpabuf_put(buf, 2);
for (i = 0; i < p->icons_count; i++) {
size_t j;
struct hs20_icon *icon = NULL;
for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
0)
icon = &bss->hs20_icons[j];
}
if (!icon)
continue; /* icon info not found */
wpabuf_put_le16(buf, icon->width);
wpabuf_put_le16(buf, icon->height);
wpabuf_put_data(buf, icon->language, 3);
wpabuf_put_u8(buf, os_strlen(icon->type));
wpabuf_put_str(buf, icon->type);
wpabuf_put_u8(buf, os_strlen(icon->name));
wpabuf_put_str(buf, icon->name);
}
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
/* OSU_NAI */
if (p->osu_nai) {
wpabuf_put_u8(buf, os_strlen(p->osu_nai));
wpabuf_put_str(buf, p->osu_nai);
} else
wpabuf_put_u8(buf, 0);
/* OSU Service Description Duples */
len2 = wpabuf_put(buf, 2);
for (i = 0; i < p->service_desc_count; i++) {
struct hostapd_lang_string *s = &p->service_desc[i];
wpabuf_put_u8(buf, 3 + s->name_len);
wpabuf_put_data(buf, s->lang, 3);
wpabuf_put_data(buf, s->name, s->name_len);
}
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
}
static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
struct wpabuf *buf)
{
if (hapd->conf->hs20_osu_providers_count) {
size_t i;
u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
wpabuf_put_u8(buf, 0); /* Reserved */
/* OSU SSID */
wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
wpabuf_put_data(buf, hapd->conf->osu_ssid,
hapd->conf->osu_ssid_len);
/* Number of OSU Providers */
wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
anqp_add_osu_provider(
buf, hapd->conf,
&hapd->conf->hs20_osu_providers[i]);
}
gas_anqp_set_element_len(buf, len);
}
}
static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
struct wpabuf *buf,
const u8 *name, size_t name_len)
{
struct hs20_icon *icon;
size_t i;
u8 *len;
wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
name, name_len);
for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
icon = &hapd->conf->hs20_icons[i];
if (name_len == os_strlen(icon->name) &&
os_memcmp(name, icon->name, name_len) == 0)
break;
}
if (i < hapd->conf->hs20_icons_count)
icon = &hapd->conf->hs20_icons[i];
else
icon = NULL;
len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
wpabuf_put_u8(buf, 0); /* Reserved */
if (icon) {
char *data;
size_t data_len;
data = os_readfile(icon->file, &data_len);
if (data == NULL || data_len > 65535) {
wpabuf_put_u8(buf, 2); /* Download Status:
* Unspecified file error */
wpabuf_put_u8(buf, 0);
wpabuf_put_le16(buf, 0);
} else {
wpabuf_put_u8(buf, 0); /* Download Status: Success */
wpabuf_put_u8(buf, os_strlen(icon->type));
wpabuf_put_str(buf, icon->type);
wpabuf_put_le16(buf, data_len);
wpabuf_put_data(buf, data, data_len);
}
os_free(data);
} else {
wpabuf_put_u8(buf, 1); /* Download Status: File not found */
wpabuf_put_u8(buf, 0);
wpabuf_put_le16(buf, 0);
}
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
struct gas_dialog_info *di,
const u8 *home_realm, size_t home_realm_len)
const u8 *home_realm, size_t home_realm_len,
const u8 *icon_name, size_t icon_name_len)
{
struct wpabuf *buf;
size_t len;
buf = wpabuf_alloc(1400);
len = 1400;
if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
len += 1000;
if (request & ANQP_REQ_ICON_REQUEST)
len += 65536;
buf = wpabuf_alloc(len);
if (buf == NULL)
return NULL;
@ -550,44 +732,32 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_connection_capability(hapd, buf);
if (request & ANQP_REQ_OPERATING_CLASS)
anqp_add_operating_class(hapd, buf);
if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
anqp_add_osu_providers_list(hapd, buf);
if (request & ANQP_REQ_ICON_REQUEST)
anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
#endif /* CONFIG_HS20 */
return buf;
}
static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
{
struct gas_dialog_info *dia = eloop_data;
wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
"dialog token %d", dia->dialog_token);
gas_serv_dialog_clear(dia);
}
struct anqp_query_info {
unsigned int request;
unsigned int remote_request;
const u8 *home_realm_query;
size_t home_realm_query_len;
u16 remote_delay;
const u8 *icon_name;
size_t icon_name_len;
int p2p_sd;
};
static void set_anqp_req(unsigned int bit, const char *name, int local,
unsigned int remote, u16 remote_delay,
struct anqp_query_info *qi)
{
qi->request |= bit;
if (local) {
wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
} else if (bit & remote) {
wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
qi->remote_request |= bit;
if (remote_delay > qi->remote_delay)
qi->remote_delay = remote_delay;
} else {
wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
}
@ -599,43 +769,38 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
{
switch (info_id) {
case ANQP_CAPABILITY_LIST:
set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
0, qi);
set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
qi);
break;
case ANQP_VENUE_NAME:
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
hapd->conf->venue_name != NULL, 0, 0, qi);
hapd->conf->venue_name != NULL, qi);
break;
case ANQP_NETWORK_AUTH_TYPE:
set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
hapd->conf->network_auth_type != NULL,
0, 0, qi);
hapd->conf->network_auth_type != NULL, qi);
break;
case ANQP_ROAMING_CONSORTIUM:
set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
hapd->conf->roaming_consortium != NULL, 0, 0, qi);
hapd->conf->roaming_consortium != NULL, qi);
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
"IP Addr Type Availability",
hapd->conf->ipaddr_type_configured,
0, 0, qi);
hapd->conf->ipaddr_type_configured, qi);
break;
case ANQP_NAI_REALM:
set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
hapd->conf->nai_realm_data != NULL,
0, 0, qi);
hapd->conf->nai_realm_data != NULL, qi);
break;
case ANQP_3GPP_CELLULAR_NETWORK:
set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
"3GPP Cellular Network",
hapd->conf->anqp_3gpp_cell_net != NULL,
0, 0, qi);
hapd->conf->anqp_3gpp_cell_net != NULL, qi);
break;
case ANQP_DOMAIN_NAME:
set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
hapd->conf->domain_name != NULL,
0, 0, qi);
hapd->conf->domain_name != NULL, qi);
break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
@ -667,29 +832,30 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
1, 0, 0, qi);
1, qi);
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
"Operator Friendly Name",
hapd->conf->hs20_oper_friendly_name != NULL,
0, 0, qi);
hapd->conf->hs20_oper_friendly_name != NULL, qi);
break;
case HS20_STYPE_WAN_METRICS:
set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
hapd->conf->hs20_wan_metrics != NULL,
0, 0, qi);
hapd->conf->hs20_wan_metrics != NULL, qi);
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
"Connection Capability",
hapd->conf->hs20_connection_capability != NULL,
0, 0, qi);
qi);
break;
case HS20_STYPE_OPERATING_CLASS:
set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
hapd->conf->hs20_operating_class != NULL,
0, 0, qi);
hapd->conf->hs20_operating_class != NULL, qi);
break;
case HS20_STYPE_OSU_PROVIDERS_LIST:
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
hapd->conf->hs20_osu_providers_count, qi);
break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
@ -716,6 +882,23 @@ static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
}
static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
const u8 *pos, const u8 *end,
struct anqp_query_info *qi)
{
qi->request |= ANQP_REQ_ICON_REQUEST;
qi->icon_name = pos;
qi->icon_name_len = end - pos;
if (hapd->conf->hs20_icons_count) {
wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
"(local)");
} else {
wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
"available");
}
}
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
const u8 *pos, const u8 *end,
struct anqp_query_info *qi)
@ -737,6 +920,21 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
return;
}
#ifdef CONFIG_P2P
if (*pos == P2P_OUI_TYPE) {
/*
* This is for P2P SD and will be taken care of by the P2P
* implementation. This query needs to be ignored in the generic
* GAS server to avoid duplicated response.
*/
wpa_printf(MSG_DEBUG,
"ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
*pos);
qi->p2p_sd = 1;
return;
}
#endif /* CONFIG_P2P */
if (*pos != HS20_ANQP_OUI_TYPE) {
wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
*pos);
@ -760,6 +958,9 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
case HS20_STYPE_NAI_HOME_REALM_QUERY:
rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
break;
case HS20_STYPE_ICON_REQUEST:
rx_anqp_hs_icon_request(hapd, pos, end, qi);
break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
"%u", subtype);
@ -772,17 +973,26 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
struct anqp_query_info *qi)
struct anqp_query_info *qi, int prot)
{
struct wpabuf *buf, *tx_buf;
buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len);
qi->home_realm_query_len,
qi->icon_name, qi->icon_name_len);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
return;
#ifdef CONFIG_P2P
if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
wpa_printf(MSG_DEBUG,
"ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
wpabuf_free(buf);
return;
}
#endif /* CONFIG_P2P */
if (wpabuf_len(buf) > hapd->gas_frag_limit ||
hapd->conf->gas_comeback_delay) {
@ -802,13 +1012,17 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
"for " MACSTR " (dialog token %u)",
MAC2STR(sa), dialog_token);
wpabuf_free(buf);
return;
tx_buf = gas_anqp_build_initial_resp_buf(
dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
0, NULL);
} else {
di->prot = prot;
di->sd_resp = buf;
di->sd_resp_pos = 0;
tx_buf = gas_anqp_build_initial_resp_buf(
dialog_token, WLAN_STATUS_SUCCESS,
comeback_delay, NULL);
}
di->sd_resp = buf;
di->sd_resp_pos = 0;
tx_buf = gas_anqp_build_initial_resp_buf(
dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
NULL);
} else {
wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
tx_buf = gas_anqp_build_initial_resp_buf(
@ -817,7 +1031,8 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
}
if (!tx_buf)
return;
if (prot)
convert_to_protected_dual(tx_buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
wpabuf_head(tx_buf), wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
@ -826,7 +1041,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
const u8 *data, size_t len)
const u8 *data, size_t len, int prot)
{
const u8 *pos = data;
const u8 *end = data + len;
@ -876,6 +1091,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
return;
wpabuf_put_data(buf, adv_proto, 2 + slen);
wpabuf_put_le16(buf, 0); /* Query Response Length */
if (prot)
convert_to_protected_dual(buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@ -927,100 +1144,13 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
pos += elen;
}
gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
}
void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
struct gas_dialog_info *dialog)
{
struct wpabuf *buf, *tx_buf;
u8 dialog_token = dialog->dialog_token;
size_t frag_len;
if (dialog->sd_resp == NULL) {
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
goto tx_gas_response_done;
dialog->sd_resp = buf;
dialog->sd_resp_pos = 0;
}
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
hapd->conf->gas_comeback_delay) {
u16 comeback_delay_tus = dialog->comeback_delay +
GAS_SERV_COMEBACK_DELAY_FUDGE;
u32 comeback_delay_secs, comeback_delay_usecs;
if (hapd->conf->gas_comeback_delay) {
/* Testing - allow overriding of the delay value */
comeback_delay_tus = hapd->conf->gas_comeback_delay;
}
wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
"%u) and comeback delay %u, "
"requesting comebacks", (unsigned int) frag_len,
(unsigned int) hapd->gas_frag_limit,
dialog->comeback_delay);
tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
WLAN_STATUS_SUCCESS,
comeback_delay_tus,
NULL);
if (tx_buf) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"GAS: Tx GAS Initial Resp (comeback = 10TU)");
hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
dst,
wpabuf_head(tx_buf),
wpabuf_len(tx_buf));
}
wpabuf_free(tx_buf);
/* start a timer of 1.5 * comeback-delay */
comeback_delay_tus = comeback_delay_tus +
(comeback_delay_tus / 2);
comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
comeback_delay_usecs = (comeback_delay_tus * 1024) -
(comeback_delay_secs * 1000000);
eloop_register_timeout(comeback_delay_secs,
comeback_delay_usecs,
gas_serv_clear_cached_ies, dialog,
NULL);
goto tx_gas_response_done;
}
buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
dialog->sd_resp_pos, frag_len);
if (buf == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
"failed");
goto tx_gas_response_done;
}
tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
WLAN_STATUS_SUCCESS, 0, buf);
wpabuf_free(buf);
if (tx_buf == NULL)
goto tx_gas_response_done;
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
"Response (frag_id %d frag_len %d)",
dialog->sd_frag_id, (int) frag_len);
dialog->sd_frag_id++;
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
wpabuf_head(tx_buf), wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
tx_gas_response_done:
gas_serv_clear_cached_ies(dialog, NULL);
gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
const u8 *data, size_t len)
const u8 *data, size_t len, int prot)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@ -1051,33 +1181,6 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
goto send_resp;
}
if (dialog->sd_resp == NULL) {
wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
dialog->requested, dialog->received);
if ((dialog->requested & dialog->received) !=
dialog->requested) {
wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
"from remote processing");
gas_serv_dialog_clear(dialog);
tx_buf = gas_anqp_build_comeback_resp_buf(
dialog_token,
WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
NULL);
if (tx_buf == NULL)
return;
goto send_resp;
}
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
goto rx_gas_comeback_req_done;
dialog->sd_resp = buf;
dialog->sd_resp_pos = 0;
}
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
if (frag_len > hapd->gas_frag_limit) {
frag_len = hapd->gas_frag_limit;
@ -1090,15 +1193,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
if (buf == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
"buffer");
goto rx_gas_comeback_req_done;
gas_serv_dialog_clear(dialog);
return;
}
tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id,
more, 0, buf);
wpabuf_free(buf);
if (tx_buf == NULL)
goto rx_gas_comeback_req_done;
if (tx_buf == NULL) {
gas_serv_dialog_clear(dialog);
return;
}
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
"(frag_id %d more=%d frag_len=%d)",
dialog->sd_frag_id, more, (int) frag_len);
@ -1118,13 +1224,11 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
}
send_resp:
if (prot)
convert_to_protected_dual(tx_buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
wpabuf_head(tx_buf), wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
return;
rx_gas_comeback_req_done:
gas_serv_clear_cached_ies(dialog, NULL);
}
@ -1133,24 +1237,30 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
{
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
size_t hdr_len;
const u8 *sa, *data;
int prot;
mgmt = (const struct ieee80211_mgmt *) buf;
hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
if (hdr_len > len)
if (len < IEEE80211_HDRLEN + 2)
return;
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
return;
/*
* Note: Public Action and Protected Dual of Public Action frames share
* the same payload structure, so it is fine to use definitions of
* Public Action frames to process both.
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
len -= hdr_len;
data = &mgmt->u.action.u.public_action.action;
len -= IEEE80211_HDRLEN + 1;
data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
break;
}
}
@ -1158,8 +1268,8 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
int gas_serv_init(struct hostapd_data *hapd)
{
hapd->public_action_cb = gas_serv_rx_public_action;
hapd->public_action_cb_ctx = hapd;
hapd->public_action_cb2 = gas_serv_rx_public_action;
hapd->public_action_cb2_ctx = hapd;
hapd->gas_frag_limit = 1400;
if (hapd->conf->gas_frag_limit > 0)
hapd->gas_frag_limit = hapd->conf->gas_frag_limit;

View File

@ -1,6 +1,6 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -37,29 +37,22 @@
(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
#define ANQP_REQ_OPERATING_CLASS \
(0x10000 << HS20_STYPE_OPERATING_CLASS)
/* To account for latencies between hostapd and external ANQP processor */
#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
#define ANQP_REQ_OSU_PROVIDERS_LIST \
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
#define ANQP_REQ_ICON_REQUEST \
(0x10000 << HS20_STYPE_ICON_REQUEST)
struct gas_dialog_info {
u8 valid;
u8 index;
struct wpabuf *sd_resp; /* Fragmented response */
u8 dialog_token;
size_t sd_resp_pos; /* Offset in sd_resp */
u8 sd_frag_id;
u16 comeback_delay;
unsigned int requested;
unsigned int received;
unsigned int all_requested;
int prot; /* whether Protected Dual of Public Action frame is used */
};
struct hostapd_data;
void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
struct gas_dialog_info *dialog);
struct gas_dialog_info *
gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
u8 dialog_token);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -10,19 +10,22 @@
#define HOSTAPD_H
#include "common/defs.h"
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
struct hostapd_data;
struct sta_info;
struct hostap_sta_driver_data;
struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
#ifdef CONFIG_MESH
struct mesh_conf;
#endif /* CONFIG_MESH */
struct hostapd_iface;
@ -40,9 +43,19 @@ struct hapd_interfaces {
int global_ctrl_sock;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
gid_t ctrl_iface_group;
#endif /* CONFIG_NATIVE_WINDOWS */
struct hostapd_iface **iface;
size_t terminate_on_error;
};
enum hostapd_chan_status {
HOSTAPD_CHAN_VALID = 0, /* channel is ready */
HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */
HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */
};
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
@ -63,6 +76,25 @@ struct hostapd_frame_info {
int ssi_signal; /* dBm */
};
enum wps_status {
WPS_STATUS_SUCCESS = 1,
WPS_STATUS_FAILURE
};
enum pbc_status {
WPS_PBC_STATUS_DISABLE,
WPS_PBC_STATUS_ACTIVE,
WPS_PBC_STATUS_TIMEOUT,
WPS_PBC_STATUS_OVERLAP
};
struct wps_stat {
enum wps_status status;
enum wps_error_indication failure_reason;
enum pbc_status pbc_status;
u8 peer_addr[ETH_ALEN];
};
/**
* struct hostapd_data - hostapd per-BSS data structure
@ -72,6 +104,9 @@ struct hostapd_data {
struct hostapd_config *iconf;
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];
@ -111,7 +146,7 @@ struct hostapd_data {
struct eapol_authenticator *eapol_auth;
struct rsn_preauth_interface *preauth_iface;
time_t michael_mic_failure;
struct os_reltime michael_mic_failure;
int michael_mic_failures;
int tkip_countermeasures;
@ -121,6 +156,7 @@ struct hostapd_data {
void *ssl_ctx;
void *eap_sim_db_priv;
struct radius_server_data *radius_srv;
struct dl_list erp_keys; /* struct eap_server_erp_key */
int parameter_set_count;
@ -143,6 +179,8 @@ struct hostapd_data {
unsigned int ap_pin_failures_consecutive;
struct upnp_wps_device_sm *wps_upnp;
unsigned int ap_pin_lockout_time;
struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
struct hostapd_probereq_cb *probereq_cb;
@ -151,6 +189,9 @@ struct hostapd_data {
void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *public_action_cb_ctx;
void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len,
int freq);
void *public_action_cb2_ctx;
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
@ -171,6 +212,22 @@ struct hostapd_data {
void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_ctx;
void (*new_psk_cb)(void *ctx, const u8 *mac_addr,
const u8 *p2p_dev_addr, const u8 *psk,
size_t psk_len);
void *new_psk_cb_ctx;
/* channel switch parameters */
struct hostapd_freq_params cs_freq_params;
u8 cs_count;
int cs_block_tx;
unsigned int cs_c_off_beacon;
unsigned int cs_c_off_proberesp;
int csa_in_progress;
/* BSS Load */
unsigned int bss_load_update_timeout;
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@ -188,10 +245,34 @@ struct hostapd_data {
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_PROXYARP
struct l2_packet_data *sock_dhcp;
struct l2_packet_data *sock_ndisc;
#endif /* CONFIG_PROXYARP */
#ifdef CONFIG_MESH
int num_plinks;
int max_plinks;
void (*mesh_sta_free_cb)(struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
#endif /* CONFIG_SQLITE */
#ifdef CONFIG_SAE
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
unsigned int ext_mgmt_frame_handling:1;
unsigned int ext_eapol_frame_io:1;
struct l2_packet_data *l2_test;
#endif /* CONFIG_TESTING_OPTIONS */
};
@ -203,16 +284,42 @@ struct hostapd_iface {
void *owner;
char *config_fname;
struct hostapd_config *conf;
char phy[16]; /* Name of the PHY (radio) */
enum hostapd_iface_state {
HAPD_IFACE_UNINITIALIZED,
HAPD_IFACE_DISABLED,
HAPD_IFACE_COUNTRY_UPDATE,
HAPD_IFACE_ACS,
HAPD_IFACE_HT_SCAN,
HAPD_IFACE_DFS,
HAPD_IFACE_ENABLED
} state;
#ifdef CONFIG_MESH
struct mesh_conf *mconf;
#endif /* CONFIG_MESH */
size_t num_bss;
struct hostapd_data **bss;
unsigned int wait_channel_update:1;
unsigned int cac_started:1;
/*
* When set, indicates that the driver will handle the AP
* teardown: delete global keys, station keys, and stations.
*/
unsigned int driver_ap_teardown:1;
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
struct ap_info *ap_iter_list;
unsigned int drv_flags;
u64 drv_flags;
/* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
unsigned int smps_modes;
/*
* A bitmap of supported protocols for probe response offload. See
@ -220,6 +327,12 @@ struct hostapd_iface {
*/
unsigned int probe_resp_offloads;
/* extended capabilities supported by the driver */
const u8 *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
unsigned int drv_max_acl_mac_addrs;
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
@ -253,11 +366,40 @@ struct hostapd_iface {
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
/* Number of HT40 intolerant stations */
int num_sta_ht40_intolerant;
/* Overlapping BSS information */
int olbc_ht;
u16 ht_op_mode;
/* surveying helpers */
/* number of channels surveyed */
unsigned int chans_surveyed;
/* lowest observed noise floor in dBm */
s8 lowest_nf;
/* channel utilization calculation */
u64 last_channel_time;
u64 last_channel_time_busy;
u8 channel_utilization;
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
/* Latched with the actual secondary channel information and will be
* used while juggling between HT20 and HT40 modes. */
int secondary_ch;
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
#endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface);
int num_ht40_scan_tries;
};
/* hostapd.c */
@ -273,6 +415,11 @@ int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
const char *config_file);
struct hostapd_iface *
hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
const char *config_fname, int debug);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@ -281,6 +428,15 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@ -296,11 +452,13 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
const u8 *addr, int reason_code);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
int offset, int width, int cf1, int cf2);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,

View File

@ -1,7 +1,7 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2009, Atheros Communications, Inc.
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -13,19 +13,165 @@
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "hs20.h"
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
{
u8 conf;
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 5;
*eid++ = 7;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
/* Hotspot Configuration: DGAF Enabled */
*eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
conf = HS20_VERSION; /* Release Number */
conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
if (hapd->conf->disable_dgaf)
conf |= HS20_DGAF_DISABLED;
*eid++ = conf;
WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
eid += 2;
return eid;
}
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
{
u8 *len;
u16 capab;
if (!hapd->conf->osen)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
len = eid++; /* to be filled */
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_OSEN_OUI_TYPE;
/* Group Data Cipher Suite */
RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
eid += RSN_SELECTOR_LEN;
/* Pairwise Cipher Suite Count and List */
WPA_PUT_LE16(eid, 1);
eid += 2;
RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
eid += RSN_SELECTOR_LEN;
/* AKM Suite Count and List */
WPA_PUT_LE16(eid, 1);
eid += 2;
RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
eid += RSN_SELECTOR_LEN;
/* RSN Capabilities */
capab = 0;
if (hapd->conf->wmm_enabled) {
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16(eid, capab);
eid += 2;
*len = eid - len - 1;
return eid;
}
int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
u8 osu_method, const char *url)
{
struct wpabuf *buf;
size_t len = 0;
int ret;
/* TODO: should refuse to send notification if the STA is not associated
* or if the STA did not indicate support for WNM-Notification */
if (url) {
len = 1 + os_strlen(url);
if (5 + len > 255) {
wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
"WNM-Notification: '%s'", url);
return -1;
}
}
buf = wpabuf_alloc(4 + 7 + len);
if (buf == NULL)
return -1;
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
wpabuf_put_u8(buf, 1); /* Dialog token */
wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
/* Subscription Remediation subelement */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, 5 + len);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
if (url) {
wpabuf_put_u8(buf, len - 1);
wpabuf_put_data(buf, url, len - 1);
wpabuf_put_u8(buf, osu_method);
} else {
/* Server URL and Server Method fields not included */
wpabuf_put_u8(buf, 0);
}
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
return ret;
}
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
const u8 *addr,
const struct wpabuf *payload)
{
struct wpabuf *buf;
int ret;
/* TODO: should refuse to send notification if the STA is not associated
* or if the STA did not indicate support for WNM-Notification */
buf = wpabuf_alloc(4 + 6 + wpabuf_len(payload));
if (buf == NULL)
return -1;
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
wpabuf_put_u8(buf, 1); /* Dialog token */
wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
/* Deauthentication Imminent Notice subelement */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, 4 + wpabuf_len(payload));
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_WNM_DEAUTH_IMMINENT_NOTICE);
wpabuf_put_buf(buf, payload);
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
return ret;
}

View File

@ -1,6 +1,6 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -12,5 +12,11 @@
struct hostapd_data;
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid);
int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
u8 osu_method, const char *url);
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
const u8 *addr,
const struct wpabuf *payload);
#endif /* HS20_H */

View File

@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -20,10 +14,14 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "acs.h"
#include "ieee802_11.h"
#include "beacon.h"
#include "hw_features.h"
@ -44,10 +42,40 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
}
#ifndef CONFIG_NO_STDOUT_DEBUG
static char * dfs_info(struct hostapd_channel_data *chan)
{
static char info[256];
char *state;
switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
case HOSTAPD_CHAN_DFS_UNKNOWN:
state = "unknown";
break;
case HOSTAPD_CHAN_DFS_USABLE:
state = "usable";
break;
case HOSTAPD_CHAN_DFS_UNAVAILABLE:
state = "unavailable";
break;
case HOSTAPD_CHAN_DFS_AVAILABLE:
state = "available";
break;
default:
return "";
}
os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
info[sizeof(info) - 1] = '\0';
return info;
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
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;
@ -70,34 +98,47 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *feature = &modes[i];
int dfs_enabled = hapd->iconf->ieee80211h &&
(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
int dfs = 0;
/*
* Disable all channels that are marked not to allow
* IBSS operation or active scanning. In addition,
* disable all channels that require radar detection,
* since that (in addition to full DFS) is not yet
* supported.
* to initiate radiation (a.k.a. passive scan and no
* IBSS).
* Use radar channels only if the driver supports DFS.
*/
if (feature->channels[j].flag &
(HOSTAPD_CHAN_NO_IBSS |
HOSTAPD_CHAN_PASSIVE_SCAN |
HOSTAPD_CHAN_RADAR))
if ((feature->channels[j].flag &
HOSTAPD_CHAN_RADAR) && dfs_enabled) {
dfs = 1;
} else if (((feature->channels[j].flag &
HOSTAPD_CHAN_RADAR) &&
!(iface->drv_flags &
WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
(feature->channels[j].flag &
HOSTAPD_CHAN_NO_IR)) {
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
}
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
"chan=%d freq=%d MHz max_tx_power=%d dBm",
"chan=%d freq=%d MHz max_tx_power=%d dBm%s",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
feature->channels[j].max_tx_power);
feature->channels[j].max_tx_power,
dfs ? dfs_info(&feature->channels[j]) : "");
}
}
return ret;
return 0;
}
@ -183,66 +224,16 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
#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 < sizeof(allowed) / sizeof(allowed[0]); k++) {
if (first == allowed[k]) {
ok = 1;
break;
}
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
iface->conf->channel,
iface->conf->secondary_channel);
return 0;
}
return 1;
return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
sec_chan);
}
@ -258,158 +249,34 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
}
static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
int *pri_chan, int *sec_chan)
{
struct ieee80211_ht_operation *oper;
struct ieee802_11_elems elems;
*pri_chan = *sec_chan = 0;
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
if (elems.ht_operation &&
elems.ht_operation_len >= sizeof(*oper)) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
*pri_chan = oper->control_chan;
if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
int sec = oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
*sec_chan = *pri_chan + 4;
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
*sec_chan = *pri_chan - 4;
}
}
}
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
int bss_pri_chan, bss_sec_chan;
size_t i;
int match;
int pri_chan, sec_chan;
int res;
pri_chan = iface->conf->channel;
sec_chan = iface->conf->secondary_channel * 4;
pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
sec_freq = pri_freq - 20;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
/*
* 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");
res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
if (res == 2)
ieee80211n_switch_pri_sec(iface);
}
/*
* Match PRI/SEC channel with any existing HT40 BSS on the same
* channels that we are about to use (if already mixed order in
* existing BSSes, use own preference).
*/
match = 0;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
if (pri_chan == bss_pri_chan &&
sec_chan == bss_sec_chan) {
match = 1;
break;
}
}
if (!match) {
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
&bss_sec_chan);
if (pri_chan == bss_sec_chan &&
sec_chan == bss_pri_chan) {
wpa_printf(MSG_INFO, "Switch own primary and "
"secondary channel due to BSS "
"overlap with " MACSTR,
MAC2STR(bss->bssid));
ieee80211n_switch_pri_sec(iface);
break;
}
}
}
return 1;
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;
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
if (sec_chan) {
if (sec_chan < pri_chan)
sec = pri - 20;
else
sec = pri + 20;
}
if ((pri < affected_start || pri > affected_end) &&
(sec < affected_start || sec > affected_end))
continue; /* not within affected channel range */
wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
" freq=%d pri=%d sec=%d",
MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
if (sec_chan) {
if (pri_freq != pri || sec_freq != sec) {
wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
"mismatch with BSS " MACSTR
" <%d,%d> (chan=%d%c) vs. <%d,%d>",
MAC2STR(bss->bssid),
pri, sec, pri_chan,
sec > pri ? '+' : '-',
pri_freq, sec_freq);
return 0;
}
}
/* TODO: 40 MHz intolerant */
}
return 1;
return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
sec_chan);
}
@ -436,6 +303,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
wpa_scan_results_free(scan_res);
iface->secondary_ch = iface->conf->secondary_channel;
if (!oper40) {
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
"channel pri=%d sec=%d based on overlapping BSSes",
@ -443,10 +311,21 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
/*
* TODO: Could consider scheduling another scan to check
* if channel width can be changed if no coex reports
* are received from associating stations.
*/
}
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
hostapd_setup_interface_complete(iface, !res);
}
@ -491,25 +370,128 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
}
static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
struct wpa_driver_scan_params *params)
{
/* Scan only the affected frequency range */
int pri_freq;
int affected_start, affected_end;
int i, pos;
struct hostapd_hw_modes *mode;
if (iface->current_mode == NULL)
return;
pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
if (iface->conf->secondary_channel > 0) {
affected_start = pri_freq - 10;
affected_end = pri_freq + 30;
} else {
affected_start = pri_freq - 30;
affected_end = pri_freq + 10;
}
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
mode = iface->current_mode;
params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
pos = 0;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (chan->freq < affected_start ||
chan->freq > affected_end)
continue;
params->freqs[pos++] = chan->freq;
}
}
static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
{
#define HT2040_COEX_SCAN_RETRY 15
struct hostapd_iface *iface = eloop_data;
struct wpa_driver_scan_params params;
int ret;
os_memset(&params, 0, sizeof(params));
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
ieee80211n_scan_channels_2g4(iface, &params);
else
ieee80211n_scan_channels_5g(iface, &params);
ret = hostapd_driver_scan(iface->bss[0], &params);
iface->num_ht40_scan_tries++;
os_free(params.freqs);
if (ret == -EBUSY &&
iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
wpa_printf(MSG_ERROR,
"Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
ret, strerror(-ret), iface->num_ht40_scan_tries);
eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
return;
}
if (ret == 0) {
iface->scan_cb = ieee80211n_check_scan;
return;
}
wpa_printf(MSG_DEBUG,
"Failed to request a scan in device, bringing up in HT20 mode");
iface->conf->secondary_channel = 0;
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
hostapd_setup_interface_complete(iface, 0);
}
void hostapd_stop_setup_timers(struct hostapd_iface *iface)
{
eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
}
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
int ret;
if (!iface->conf->secondary_channel)
return 0; /* HT40 not used */
hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(&params, 0, sizeof(params));
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
ieee80211n_scan_channels_2g4(iface, &params);
if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
os_free(params.freqs);
else
ieee80211n_scan_channels_5g(iface, &params);
ret = hostapd_driver_scan(iface->bss[0], &params);
os_free(params.freqs);
if (ret == -EBUSY) {
wpa_printf(MSG_ERROR,
"Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
ret, strerror(-ret));
iface->num_ht40_scan_tries = 1;
eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
return 1;
}
if (ret < 0) {
wpa_printf(MSG_ERROR,
"Failed to request a scan of neighboring BSSes ret=%d (%s)",
ret, strerror(-ret));
return -1;
}
os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
@ -535,11 +517,24 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
(conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SMPS-*]");
return 0;
switch (conf & HT_CAP_INFO_SMPS_MASK) {
case HT_CAP_INFO_SMPS_STATIC:
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
wpa_printf(MSG_ERROR,
"Driver does not support configured HT capability [SMPS-STATIC]");
return 0;
}
break;
case HT_CAP_INFO_SMPS_DYNAMIC:
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
wpa_printf(MSG_ERROR,
"Driver does not support configured HT capability [SMPS-DYNAMIC]");
return 0;
}
break;
case HT_CAP_INFO_SMPS_DISABLED:
default:
break;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
@ -597,12 +592,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [PSMP]");
return 0;
}
if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
!(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@ -613,6 +602,112 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 1;
}
#ifdef CONFIG_IEEE80211AC
static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
{
u32 req_cap = conf & cap;
/*
* Make sure we support all requested capabilities.
* NOTE: We assume that 'cap' represents a capability mask,
* not a discrete value.
*/
if ((hw & req_cap) != req_cap) {
wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
name);
return 0;
}
return 1;
}
static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
unsigned int shift,
const char *name)
{
u32 hw_max = hw & mask;
u32 conf_val = conf & mask;
if (conf_val > hw_max) {
wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
name, conf_val >> shift, hw_max >> shift);
return 0;
}
return 1;
}
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
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)) \
return 0; \
} while (0)
#define VHT_CAP_CHECK_MAX(cap) \
do { \
if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
#cap)) \
return 0; \
} while (0)
VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
VHT_CAP_CHECK(VHT_CAP_RXLDPC);
VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
VHT_CAP_CHECK(VHT_CAP_TXSTBC);
VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
#undef VHT_CAP_CHECK
#undef VHT_CAP_CHECK_MAX
return 1;
}
#endif /* CONFIG_IEEE80211AC */
#endif /* CONFIG_IEEE80211N */
@ -624,6 +719,10 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AC
if (!ieee80211ac_supported_vht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface);
if (ret)
return ret;
@ -635,6 +734,129 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
}
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->chan != channel)
continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
return 1;
wpa_printf(MSG_DEBUG,
"%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
primary ? "" : "Configured HT40 secondary ",
i, chan->chan, chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
}
return 0;
}
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
if (!iface->conf->secondary_channel)
return 1;
return hostapd_is_usable_chan(iface, iface->conf->channel +
iface->conf->secondary_channel * 4, 0);
}
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
if (iface->conf->channel) {
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
return HOSTAPD_CHAN_INVALID;
}
/*
* The user set channel=0 or channel=acs_survey
* which is used to trigger ACS.
*/
switch (acs_init(iface)) {
case HOSTAPD_CHAN_ACS:
return HOSTAPD_CHAN_ACS;
case HOSTAPD_CHAN_VALID:
case HOSTAPD_CHAN_INVALID:
default:
return HOSTAPD_CHAN_INVALID;
}
}
static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
{
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured channel (%d) not found from the "
"channel list of current mode (%d) %s",
iface->conf->channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
}
int hostapd_acs_completed(struct hostapd_iface *iface, int err)
{
int ret = -1;
if (err)
goto out;
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
hostapd_hw_get_freq(iface->bss[0],
iface->conf->channel),
iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
hostapd_notify_bad_chans(iface);
goto out;
case HOSTAPD_CHAN_INVALID:
default:
wpa_printf(MSG_ERROR, "ACS picked unusable channels");
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
hostapd_notify_bad_chans(iface);
goto out;
}
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto out;
if (ret == 1) {
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
return 0;
}
ret = 0;
out:
return hostapd_setup_interface_complete(iface, ret);
}
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
@ -645,11 +867,20 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
*/
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i, j, ok;
int i;
if (iface->num_hw_features < 1)
return -1;
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
iface->conf->channel == 14) {
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
}
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
@ -670,82 +901,16 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
return -2;
}
ok = 0;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (chan->chan == iface->conf->channel) {
if (chan->flag & HOSTAPD_CHAN_DISABLED) {
wpa_printf(MSG_ERROR,
"channel [%i] (%i) is disabled for "
"use in AP mode, flags: 0x%x%s%s%s",
j, chan->chan, chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IBSS ?
" NO-IBSS" : "",
chan->flag &
HOSTAPD_CHAN_PASSIVE_SCAN ?
" PASSIVE-SCAN" : "",
chan->flag & HOSTAPD_CHAN_RADAR ?
" RADAR" : "");
} else {
ok = 1;
break;
}
}
}
if (ok && iface->conf->secondary_channel) {
int sec_ok = 0;
int sec_chan = iface->conf->channel +
iface->conf->secondary_channel * 4;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->chan == sec_chan)) {
sec_ok = 1;
break;
}
}
if (!sec_ok) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured HT40 secondary channel "
"(%d) not found from the channel list "
"of current mode (%d) %s",
sec_chan, iface->current_mode->mode,
hostapd_hw_mode_txt(
iface->current_mode->mode));
ok = 0;
}
}
if (iface->conf->channel == 0) {
/* TODO: could request a scan of neighboring BSSes and select
* the channel automatically */
wpa_printf(MSG_ERROR, "Channel not configured "
"(hw_mode/channel in hostapd.conf)");
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
return 0;
case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
return 1;
case HOSTAPD_CHAN_INVALID:
default:
hostapd_notify_bad_chans(iface);
return -3;
}
if (ok == 0 && iface->conf->channel != 0) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured channel (%d) not found from the "
"channel list of current mode (%d) %s",
iface->conf->channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
iface->current_mode = NULL;
}
if (iface->current_mode == NULL) {
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
return -4;
}
return 0;
}
@ -768,35 +933,11 @@ const char * hostapd_hw_mode_txt(int mode)
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);
}

View File

@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef HW_FEATURES_H
@ -21,6 +15,7 @@
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
int hostapd_acs_completed(struct hostapd_iface *iface, int err);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
@ -28,6 +23,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@ -66,6 +62,10 @@ static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
return 0;
}
static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
{
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */

View File

@ -204,7 +204,7 @@ static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
addr.sin_port = htons(IAPP_UDP_PORT);
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
(struct sockaddr *) &addr, sizeof(addr)) < 0)
perror("sendto[IAPP-ADD]");
wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
}
@ -231,7 +231,7 @@ static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
* FIX: what is correct RW with 802.11? */
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
perror("send[L2 Update]");
wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
}
@ -242,29 +242,22 @@ static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
*/
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
{
struct ieee80211_mgmt *assoc;
u16 seq;
u16 seq = 0; /* TODO */
if (iapp == NULL)
return;
assoc = sta->last_assoc_req;
seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
iapp_send_layer2_update(iapp, sta->addr);
iapp_send_add(iapp, sta->addr, seq);
if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
WLAN_FC_STYPE_REASSOC_REQ) {
/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
* Context Block, Timeout)
*/
/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
* IP address */
}
/* TODO: If this was reassociation:
* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
* Context Block, Timeout)
* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
* IP address */
}
@ -276,8 +269,8 @@ static void iapp_process_add_notify(struct iapp_data *iapp,
struct sta_info *sta;
if (len != sizeof(*add)) {
printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
len, (unsigned long) sizeof(*add));
wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
len, (unsigned long) sizeof(*add));
return;
}
@ -326,7 +319,8 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
(struct sockaddr *) &from, &fromlen);
if (len < 0) {
perror("recvfrom");
wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
strerror(errno));
return;
}
@ -350,23 +344,24 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
hdr->version, hdr->command,
be_to_host16(hdr->identifier), hlen);
if (hdr->version != IAPP_VERSION) {
printf("Dropping IAPP frame with unknown version %d\n",
hdr->version);
wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
hdr->version);
return;
}
if (hlen > len) {
printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
hlen, len);
return;
}
if (hlen < len) {
printf("Ignoring %d extra bytes from IAPP frame\n",
len - hlen);
wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
len - hlen);
len = hlen;
}
switch (hdr->command) {
case IAPP_CMD_ADD_notify:
iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
break;
case IAPP_CMD_MOVE_notify:
/* TODO: MOVE is using TCP; so move this to TCP handler once it
@ -376,7 +371,7 @@ static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
/* TODO: process */
break;
default:
printf("Unknown IAPP command %d\n", hdr->command);
wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
break;
}
}
@ -403,7 +398,8 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (iapp->udp_sock < 0) {
perror("socket[PF_INET,SOCK_DGRAM]");
wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@ -411,35 +407,38 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
perror("ioctl(SIOCGIFINDEX)");
wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
ifindex = ifr.ifr_ifindex;
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFADDR)");
wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFADDR)\n",
paddr->sin_family);
wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
iapp->own.s_addr = paddr->sin_addr.s_addr;
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFBRDADDR)");
wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
paddr->sin_family);
wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
@ -450,7 +449,8 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
uaddr.sin_port = htons(IAPP_UDP_PORT);
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
perror("bind[UDP]");
wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@ -461,14 +461,16 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (iapp->packet_sock < 0) {
perror("socket[PF_PACKET,SOCK_RAW]");
wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
@ -478,19 +480,20 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
addr.sll_ifindex = ifindex;
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
perror("bind[PACKET]");
wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
strerror(errno));
iapp_deinit(iapp);
return NULL;
}
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
iapp, NULL)) {
printf("Could not register read socket for IAPP.\n");
wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
iapp_deinit(iapp);
return NULL;
}
printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
@ -515,7 +518,8 @@ void iapp_deinit(struct iapp_data *iapp)
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
strerror(errno));
}
eloop_unregister_read_sock(iapp->udp_sock);

File diff suppressed because it is too large Load Diff

View File

@ -14,12 +14,14 @@ struct hostapd_data;
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_mgmt;
void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
u16 stype, int ok);
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
void hostapd_2040_coex_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@ -40,24 +42,37 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
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);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
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);
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
void hostapd_get_vht_capab(struct hostapd_data *hapd,
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);
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);
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,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@ -78,4 +93,15 @@ int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
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 */

View File

@ -29,7 +29,7 @@
struct hostapd_cached_radius_acl {
os_time_t timestamp;
struct os_reltime timestamp;
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
@ -43,7 +43,7 @@ struct hostapd_cached_radius_acl {
struct hostapd_acl_query_data {
os_time_t timestamp;
struct os_reltime timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@ -104,15 +104,16 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
struct os_reltime now;
os_get_time(&now);
os_get_reltime(&now);
for (entry = hapd->acl_cache; entry; entry = entry->next) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
continue;
if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
@ -265,7 +266,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
struct os_time t;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
@ -305,8 +305,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
os_get_time(&t);
query->timestamp = t.sec;
os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@ -338,7 +337,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
struct os_reltime *now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
@ -346,7 +346,8 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
entry = hapd->acl_cache;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
if (os_reltime_expired(now, &entry->timestamp,
RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@ -367,7 +368,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
os_time_t now)
struct os_reltime *now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
@ -375,7 +376,8 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
entry = hapd->acl_queries;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
if (os_reltime_expired(now, &entry->timestamp,
RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@ -403,11 +405,11 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct os_time now;
struct os_reltime now;
os_get_time(&now);
hostapd_acl_expire_cache(hapd, now.sec);
hostapd_acl_expire_queries(hapd, now.sec);
os_get_reltime(&now);
hostapd_acl_expire_cache(hapd, &now);
hostapd_acl_expire_queries(hapd, &now);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
@ -480,7 +482,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
struct os_time t;
query = hapd->acl_queries;
prev = NULL;
@ -515,8 +516,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
os_get_time(&t);
cache->timestamp = t.sec;
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;

View File

@ -3,26 +3,22 @@
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
#include "hw_features.h"
#include "ap_drv_ops.h"
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
@ -50,6 +46,35 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
pos += sizeof(*cap);
if (hapd->iconf->obss_interval) {
struct ieee80211_obss_scan_parameters *scan_params;
*pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS;
*pos++ = sizeof(*scan_params);
scan_params = (struct ieee80211_obss_scan_parameters *) pos;
os_memset(scan_params, 0, sizeof(*scan_params));
scan_params->width_trigger_scan_interval =
host_to_le16(hapd->iconf->obss_interval);
/* Fill in default values for remaining parameters
* (IEEE Std 802.11-2012, 8.4.2.61 and MIB defval) */
scan_params->scan_passive_dwell =
host_to_le16(20);
scan_params->scan_active_dwell =
host_to_le16(10);
scan_params->scan_passive_total_per_channel =
host_to_le16(200);
scan_params->scan_active_total_per_channel =
host_to_le16(20);
scan_params->channel_transition_delay_factor =
host_to_le16(5);
scan_params->scan_activity_threshold =
host_to_le16(25);
pos += sizeof(*scan_params);
}
return pos;
}
@ -68,14 +93,14 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
oper = (struct ieee80211_ht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
oper->control_chan = hapd->iconf->channel;
oper->primary_chan = hapd->iconf->channel;
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
if (hapd->iconf->secondary_channel == 1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
if (hapd->iconf->secondary_channel == -1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
pos += sizeof(*oper);
@ -105,45 +130,40 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
__func__, iface->ht_op_mode);
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
if (!(iface->ht_op_mode & HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT)
&& iface->num_sta_ht_no_gf) {
iface->ht_op_mode |=
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
iface->ht_op_mode |= HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT) &&
iface->num_sta_ht_no_gf == 0) {
iface->ht_op_mode &=
~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
iface->ht_op_mode &= ~HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT;
op_mode_changes++;
}
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
if (!(iface->ht_op_mode & HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) &&
(iface->num_sta_no_ht || iface->olbc_ht)) {
iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
iface->ht_op_mode |= HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) &&
(iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
iface->ht_op_mode &=
~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
iface->ht_op_mode &= ~HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT;
op_mode_changes++;
}
new_op_mode = 0;
if (iface->num_sta_no_ht)
new_op_mode = OP_MODE_MIXED;
else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
&& iface->num_sta_ht_20mhz)
new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
new_op_mode = HT_PROT_NON_HT_MIXED;
else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz)
new_op_mode = HT_PROT_20MHZ_PROTECTION;
else if (iface->olbc_ht)
new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
new_op_mode = HT_PROT_NONMEMBER_PROTECTION;
else
new_op_mode = OP_MODE_PURE;
new_op_mode = HT_PROT_NO_PROTECTION;
cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
cur_op_mode = iface->ht_op_mode & HT_OPER_OP_MODE_HT_PROT_MASK;
if (cur_op_mode != new_op_mode) {
iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
iface->ht_op_mode &= ~HT_OPER_OP_MODE_HT_PROT_MASK;
iface->ht_op_mode |= new_op_mode;
op_mode_changes++;
}
@ -155,6 +175,140 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
}
static int is_40_allowed(struct hostapd_iface *iface, int channel)
{
int pri_freq, sec_freq;
int affected_start, affected_end;
int pri = 2407 + 5 * channel;
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return 1;
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;
if ((pri < affected_start || pri > affected_end))
return 1; /* not within affected channel range */
wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri);
return 0;
}
void hostapd_2040_coex_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
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 i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
mgmt->u.action.u.public_action.action);
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
return;
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
return;
bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
bc_ie->length < 1) {
wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
bc_ie->element_id, bc_ie->length);
return;
}
if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
return;
data += 2 + bc_ie->length;
wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
bc_ie->coex_param);
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20 MHz BSS width request bit is set in BSS coexistence information field");
is_ht_allowed = 0;
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"40 MHz intolerant bit is set in BSS coexistence information field");
is_ht_allowed = 0;
}
if (start + len - data >= 3 &&
data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
u8 ielen = data[1];
if (ielen > start + len - data - 2)
return;
ic_report = (struct ieee80211_2040_intol_chan_report *) data;
wpa_printf(MSG_DEBUG,
"20/40 BSS Intolerant Channel Report: Operating Class %u",
ic_report->op_class);
/* Go through the channel report to find any BSS there in the
* affected channel range */
for (i = 0; i < ielen - 1; i++) {
u8 chan = ic_report->variable[i];
if (is_40_allowed(iface, chan))
continue;
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20_40_INTOLERANT channel %d reported",
chan);
is_ht_allowed = 0;
}
}
wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
is_ht_allowed, iface->num_sta_ht40_intolerant);
if (!is_ht_allowed &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
if (iface->conf->secondary_channel) {
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"Switching to 20 MHz operation");
iface->conf->secondary_channel = 0;
ieee802_11_set_beacons(iface);
}
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;
eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
NULL);
eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
hapd->iface, NULL);
wpa_printf(MSG_DEBUG,
"Reschedule HT 20/40 timeout to occur in %u seconds",
delay_time);
}
}
}
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
@ -183,6 +337,52 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta)
{
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return;
wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
" in Association Request", MAC2STR(sta->addr));
if (sta->ht40_intolerant_set)
return;
sta->ht40_intolerant_set = 1;
iface->num_sta_ht40_intolerant++;
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
if (iface->conf->secondary_channel &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
iface->conf->secondary_channel = 0;
ieee802_11_set_beacons(iface);
}
}
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta)
{
if (!sta->ht40_intolerant_set)
return;
sta->ht40_intolerant_set = 0;
iface->num_sta_ht40_intolerant--;
if (iface->num_sta_ht40_intolerant == 0 &&
(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
iface->conf->obss_interval;
wpa_printf(MSG_DEBUG,
"HT: Start 20->40 MHz transition timer (%d seconds)",
delay_time);
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
iface, NULL);
}
}
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
u16 ht_capab;
@ -210,6 +410,9 @@ static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT)
ht40_intolerant_add(hapd->iface, sta);
}
@ -271,3 +474,14 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
}
void ap_ht2040_timeout(void *eloop_data, void *user_data)
{
struct hostapd_iface *iface = eloop_data;
wpa_printf(MSG_INFO, "Switching to 40 MHz operation");
iface->conf->secondary_channel = iface->secondary_ch;
ieee802_11_set_beacons(iface);
}

View File

@ -24,13 +24,13 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
{
u8 *pos = eid;
u32 timeout, tu;
struct os_time now, passed;
struct os_reltime now, passed;
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
os_get_reltime(&now);
os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout > tu)
timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
@ -69,7 +69,7 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
WLAN_SA_QUERY_TR_ID_LEN);
end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
perror("ieee802_11_send_sa_query_req: send");
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
}
@ -107,7 +107,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
WLAN_SA_QUERY_TR_ID_LEN);
end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
perror("ieee80211_mgmt_sa_query_request: send");
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
}
@ -164,10 +164,62 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
#endif /* CONFIG_IEEE80211W */
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
*pos = 0x00;
switch (idx) {
case 0: /* Bits 0-7 */
if (hapd->iconf->obss_interval)
*pos |= 0x01; /* Bit 0 - Coexistence management */
break;
case 1: /* Bits 8-15 */
if (hapd->conf->proxy_arp)
*pos |= 0x10; /* Bit 12 - Proxy ARP */
break;
case 2: /* Bits 16-23 */
if (hapd->conf->wnm_sleep_mode)
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
if (hapd->conf->bss_transition)
*pos |= 0x08; /* Bit 19 - BSS Transition */
break;
case 3: /* Bits 24-31 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 25 - SSID List */
#endif /* CONFIG_WNM */
if (hapd->conf->time_advertisement == 2)
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
if (hapd->conf->interworking)
*pos |= 0x80; /* Bit 31 - Interworking */
break;
case 4: /* Bits 32-39 */
if (hapd->conf->qos_map_set_len)
*pos |= 0x01; /* Bit 32 - QoS Map */
if (hapd->conf->tdls & TDLS_PROHIBIT)
*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
/* Bit 39 - TDLS Channel Switching Prohibited */
*pos |= 0x80;
}
break;
case 5: /* Bits 40-47 */
#ifdef CONFIG_HS20
if (hapd->conf->hs20)
*pos |= 0x40; /* Bit 46 - WNM-Notification */
#endif /* CONFIG_HS20 */
break;
case 6: /* Bits 48-55 */
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
break;
}
}
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
u8 len = 0;
u8 len = 0, i;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
@ -175,59 +227,57 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
len = 4;
if (len < 3 && hapd->conf->wnm_sleep_mode)
len = 3;
if (len < 1 && hapd->iconf->obss_interval)
len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
#ifdef CONFIG_WNM
if (len < 4)
len = 4;
#endif /* CONFIG_WNM */
#ifdef CONFIG_HS20
if (hapd->conf->hs20 && len < 6)
len = 6;
#endif /* CONFIG_HS20 */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
*pos++ = 0x00;
*pos++ = 0x00;
for (i = 0; i < len; i++, pos++) {
hostapd_ext_capab_byte(hapd, pos, i);
*pos = 0x00;
if (hapd->conf->wnm_sleep_mode)
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
if (hapd->conf->bss_transition)
*pos |= 0x08; /* Bit 19 - BSS Transition */
pos++;
if (i < hapd->iface->extended_capa_len) {
*pos &= ~hapd->iface->extended_capa_mask[i];
*pos |= hapd->iface->extended_capa[i];
}
}
if (len < 4)
return pos;
*pos = 0x00;
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 25 - SSID List */
#endif /* CONFIG_WNM */
if (hapd->conf->time_advertisement == 2)
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
if (hapd->conf->interworking)
*pos |= 0x80; /* Bit 31 - Interworking */
pos++;
while (len > 0 && eid[1 + len] == 0) {
len--;
eid[1] = len;
}
if (len == 0)
return eid;
if (len < 5)
return pos;
*pos = 0x00;
if (hapd->conf->tdls & TDLS_PROHIBIT)
*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
pos++;
return eid + 2 + len;
}
if (len < 6)
return pos;
*pos = 0x00;
pos++;
if (len < 7)
return pos;
*pos = 0x00;
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
pos++;
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
u8 len = hapd->conf->qos_map_set_len;
if (!len)
return eid;
*pos++ = WLAN_EID_QOS_MAP_SET;
*pos++ = len;
os_memcpy(pos, hapd->conf->qos_map_set, len);
pos += len;
return pos;
}

View File

@ -12,7 +12,6 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
@ -23,23 +22,35 @@
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);
cap = (struct ieee80211_vht_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
cap->vht_capabilities_info = host_to_le32(
hapd->iface->current_mode->vht_capab);
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);
@ -52,9 +63,6 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
return eid;
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@ -82,13 +90,55 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
}
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)
{
/* 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;
@ -108,3 +158,140 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
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)
{
if (!vht_oper_notif) {
sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
return WLAN_STATUS_SUCCESS;
}
sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
sta->vht_opmode = *vht_oper_notif;
return WLAN_STATUS_SUCCESS;
}
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap)
{
u32 cap, own_cap, sym_caps;
if (vht_cap == NULL)
return;
os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
own_cap = hapd->iconf->vht_capab;
/* mask out symmetric VHT capabilities we don't support */
sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
cap &= ~sym_caps | (own_cap & sym_caps);
/* mask out beamformer/beamformee caps if not supported */
if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
VHT_CAP_BEAMFORMEE_STS_MAX);
if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
VHT_CAP_SOUNDING_DIMENSION_MAX);
if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
/* mask channel widths we don't support */
switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
break;
case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
}
break;
default:
cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
break;
}
if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
cap &= ~VHT_CAP_SHORT_GI_160;
/*
* if we don't support RX STBC, mask out TX STBC in the STA's HT caps
* if we don't support TX STBC, mask out RX STBC in the STA's HT caps
*/
if (!(own_cap & VHT_CAP_RXSTBC_MASK))
cap &= ~VHT_CAP_TXSTBC;
if (!(own_cap & VHT_CAP_TXSTBC))
cap &= ~VHT_CAP_RXSTBC_MASK;
neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
}

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
int ieee802_1x_init(struct hostapd_data *hapd);
void ieee802_1x_erp_flush(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);

View File

@ -0,0 +1,171 @@
/*
* Neighbor Discovery snooping for Proxy ARP
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include "utils/common.h"
#include "l2_packet/l2_packet.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_drv_ops.h"
#include "list.h"
#include "x_snoop.h"
struct ip6addr {
struct in6_addr addr;
struct dl_list list;
};
struct icmpv6_ndmsg {
struct ip6_hdr ipv6h;
struct icmp6_hdr icmp6h;
struct in6_addr target_addr;
u8 opt_type;
u8 len;
u8 opt_lladdr[0];
} STRUCT_PACKED;
#define ROUTER_ADVERTISEMENT 134
#define NEIGHBOR_SOLICITATION 135
#define NEIGHBOR_ADVERTISEMENT 136
#define SOURCE_LL_ADDR 1
static int sta_ip6addr_add(struct sta_info *sta, struct in6_addr *addr)
{
struct ip6addr *ip6addr;
ip6addr = os_zalloc(sizeof(*ip6addr));
if (!ip6addr)
return -1;
os_memcpy(&ip6addr->addr, addr, sizeof(*addr));
dl_list_add_tail(&sta->ip6addr, &ip6addr->list);
return 0;
}
void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct ip6addr *ip6addr, *prev;
dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
list) {
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
os_free(ip6addr);
}
}
static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
{
struct ip6addr *ip6addr;
dl_list_for_each(ip6addr, &sta->ip6addr, struct ip6addr, list) {
if (ip6addr->addr.s6_addr32[0] == addr->s6_addr32[0] &&
ip6addr->addr.s6_addr32[1] == addr->s6_addr32[1] &&
ip6addr->addr.s6_addr32[2] == addr->s6_addr32[2] &&
ip6addr->addr.s6_addr32[3] == addr->s6_addr32[3])
return 1;
}
return 0;
}
static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
struct hostapd_data *hapd = ctx;
struct icmpv6_ndmsg *msg;
struct in6_addr *saddr;
struct sta_info *sta;
int res;
char addrtxt[INET6_ADDRSTRLEN + 1];
if (len < ETH_HLEN + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
return;
msg = (struct icmpv6_ndmsg *) &buf[ETH_HLEN];
switch (msg->icmp6h.icmp6_type) {
case NEIGHBOR_SOLICITATION:
if (len < ETH_HLEN + sizeof(*msg))
return;
if (msg->opt_type != SOURCE_LL_ADDR)
return;
saddr = &msg->ipv6h.ip6_src;
if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
return;
sta = ap_get_sta(hapd, msg->opt_lladdr);
if (!sta)
return;
if (sta_has_ip6addr(sta, saddr))
return;
if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
== NULL)
addrtxt[0] = '\0';
wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
MACSTR, addrtxt, MAC2STR(sta->addr));
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
128, sta->addr);
if (res) {
wpa_printf(MSG_ERROR,
"ndisc_snoop: Adding ip neigh failed: %d",
res);
return;
}
if (sta_ip6addr_add(sta, saddr))
return;
}
break;
case ROUTER_ADVERTISEMENT:
if (!hapd->conf->disable_dgaf)
return;
/* fall through */
case NEIGHBOR_ADVERTISEMENT:
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
continue;
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
(u8 *) buf, len);
}
break;
default:
break;
}
}
int ndisc_snoop_init(struct hostapd_data *hapd)
{
hapd->sock_ndisc = x_snoop_get_l2_packet(hapd, handle_ndisc,
L2_PACKET_FILTER_NDISC);
if (hapd->sock_ndisc == NULL) {
wpa_printf(MSG_DEBUG,
"ndisc_snoop: Failed to initialize L2 packet processing for NDISC packets: %s",
strerror(errno));
return -1;
}
return 0;
}
void ndisc_snoop_deinit(struct hostapd_data *hapd)
{
l2_packet_deinit(hapd->sock_ndisc);
}

View File

@ -0,0 +1,36 @@
/*
* Neighbor Discovery snooping for Proxy ARP
* Copyright (c) 2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef NDISC_SNOOP_H
#define NDISC_SNOOP_H
#if defined(CONFIG_PROXYARP) && defined(CONFIG_IPV6)
int ndisc_snoop_init(struct hostapd_data *hapd);
void ndisc_snoop_deinit(struct hostapd_data *hapd);
void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_PROXYARP && CONFIG_IPV6 */
static inline int ndisc_snoop_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void ndisc_snoop_deinit(struct hostapd_data *hapd)
{
}
static inline void sta_ip6addr_del(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
#endif /* CONFIG_PROXYARP && CONFIG_IPV6 */
#endif /* NDISC_SNOOP_H */

View File

@ -96,9 +96,8 @@ u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
u8 bitmap;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 4 + 3 + 1;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = P2P_OUI_TYPE;
WPA_PUT_BE32(eid, P2P_IE_VENDOR_TYPE);
eid += 4;
*eid++ = P2P_ATTR_MANAGEABILITY;
WPA_PUT_LE16(eid, 1);

View File

@ -79,15 +79,15 @@ static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 *buf, *pos;
size_t buf_len;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
return;
}
@ -221,8 +221,8 @@ static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
return;
/* Peer RSN IE */
os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
pos = buf + kde->rsn_ie_len;
os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
pos += kde->rsn_ie_len;
/* Peer MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
@ -253,14 +253,14 @@ static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
return;
}
@ -324,15 +324,15 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
struct wpa_state_machine *sm,
const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
struct rsn_error_kde error;
u16 mui, error_type;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
return;
}

View File

@ -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"
@ -37,53 +38,55 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
if (entry == NULL)
return;
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
os_free(entry);
bin_clear_free(entry, sizeof(*entry));
}
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
unsigned int hash;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
/* unlink from hash list */
hash = PMKID_HASH(entry->pmkid);
pos = pmksa->pmkid[hash];
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL) {
prev->hnext = pos->hnext;
} else {
pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
pos->hnext;
}
if (prev != NULL)
prev->hnext = entry->hnext;
else
pmksa->pmkid[hash] = entry->hnext;
break;
}
prev = pos;
pos = pos->hnext;
}
/* unlink from entry list */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL)
prev->next = pos->next;
prev->next = entry->next;
else
pmksa->pmksa = pos->next;
pmksa->pmksa = entry->next;
break;
}
prev = pos;
pos = pos->next;
}
_pmksa_cache_free_entry(entry);
}
@ -91,9 +94,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
struct os_time now;
struct os_reltime now;
os_get_time(&now);
os_get_reltime(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(pmksa->pmksa->spa));
@ -107,12 +110,12 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct os_time now;
struct os_reltime now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
os_get_time(&now);
os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
@ -144,6 +147,9 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
entry->eap_type_authsrv = eapol->eap_type_authsrv;
entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
}
@ -181,6 +187,9 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
eapol->eap_type_authsrv = entry->eap_type_authsrv;
((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
}
@ -188,6 +197,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
int hash;
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
@ -205,8 +215,10 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
entry->next = prev->next;
prev->next = entry;
}
entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
hash = PMKID_HASH(entry->pmkid);
entry->hnext = pmksa->pmkid[hash];
pmksa->pmkid[hash] = entry;
pmksa->pmksa_count++;
if (prev == NULL)
@ -222,6 +234,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @session_timeout: Session timeout
@ -237,23 +251,32 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_time now;
struct os_reltime now;
if (pmk_len > PMK_LEN)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
os_get_time(&now);
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,
wpa_key_mgmt_sha256(akmp));
os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
entry->expiration += session_timeout;
@ -342,6 +365,8 @@ void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
pmksa->pmksa_count = 0;
pmksa->pmksa = NULL;
for (i = 0; i < PMKID_HASH_SIZE; i++)
pmksa->pmkid[i] = NULL;
os_free(pmksa);
@ -361,18 +386,22 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *entry;
if (pmkid)
entry = pmksa->pmkid[PMKID_HASH(pmkid)];
else
entry = pmksa->pmksa;
while (entry) {
if ((spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
return entry;
entry = pmkid ? entry->hnext : entry->next;
if (pmkid) {
for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
entry = entry->hnext) {
if ((spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
return entry;
}
} else {
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
return entry;
}
}
return NULL;
}
@ -394,15 +423,13 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *entry;
u8 new_pmkid[PMKID_LEN];
entry = pmksa->pmksa;
while (entry) {
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
wpa_key_mgmt_sha256(entry->akmp));
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
@ -428,3 +455,74 @@ pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
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;
}

View File

@ -30,6 +30,9 @@ struct rsn_pmksa_cache_entry {
u8 eap_type_authsrv;
int vlan_id;
int opportunistic;
u32 acct_multi_session_id_hi;
u32 acct_multi_session_id_lo;
};
struct rsn_pmksa_cache;
@ -47,6 +50,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
@ -55,5 +59,9 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid);
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
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 */

View File

@ -1,6 +1,6 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -12,9 +12,9 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
@ -30,11 +30,14 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "gas_serv.h"
#include "wnm_ap.h"
#include "ndisc_snoop.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
@ -69,6 +72,30 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
}
#ifdef CONFIG_P2P
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
const u8 *p2p_dev_addr;
if (sta->p2p_ie == NULL)
continue;
p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
if (p2p_dev_addr == NULL)
continue;
if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
return sta;
}
return NULL;
}
#endif /* CONFIG_P2P */
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *tmp;
@ -118,6 +145,12 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
}
void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
{
sta_ip6addr_del(hapd, sta);
}
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@ -128,9 +161,14 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
ap_sta_set_authorized(hapd, sta, 0);
if (sta->flags & WLAN_STA_WDS)
hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (!(sta->flags & WLAN_STA_PREAUTH))
if (sta->ipaddr)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
if (!hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);
@ -179,6 +217,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hapd->iface->num_sta_ht_20mhz--;
}
#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
@ -193,6 +235,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
hapd->mesh_sta_free_cb(sta);
#endif /* CONFIG_MESH */
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
@ -200,17 +247,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
__func__, MAC2STR(sta->addr));
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_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);
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
radius_client_flush_auth(hapd->radius, sta->addr);
if (hapd->radius)
radius_client_flush_auth(hapd->radius, sta->addr);
#endif /* CONFIG_NO_RADIUS */
os_free(sta->last_assoc_req);
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
@ -236,9 +285,18 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->hs20_ie);
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
os_free(sta->remediation_url);
wpabuf_free(sta->hs20_deauth_req);
os_free(sta->hs20_session_info_url);
#ifdef CONFIG_SAE
sae_clear_data(sta->sae);
os_free(sta->sae);
#endif /* CONFIG_SAE */
os_free(sta);
}
@ -277,6 +335,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
int reason;
wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
__func__, MAC2STR(sta->addr), sta->flags,
@ -311,8 +370,15 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
* 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_DEBUG,
"Station " MACSTR " has been active %is ago",
@ -344,6 +410,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
next_time = hapd->conf->ap_max_inactivity;
}
skip_poll:
if (next_time) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%lu seconds)",
@ -372,9 +439,11 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
} else {
hostapd_drv_sta_disassoc(
hapd, sta->addr,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
reason = (sta->timeout_next == STA_DISASSOC) ?
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
WLAN_REASON_PREV_AUTH_NOT_VALID;
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
}
}
@ -388,6 +457,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hapd, sta);
break;
case STA_DISASSOC:
case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@ -399,14 +469,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
reason = (sta->timeout_next == STA_DISASSOC) ?
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
WLAN_REASON_PREV_AUTH_NOT_VALID;
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
__func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
mlme_disassociate_indication(hapd, sta, reason);
break;
case STA_DEAUTH:
case STA_REMOVE:
@ -429,7 +501,6 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
@ -440,6 +511,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
return;
}
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@ -447,9 +520,19 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
"session timeout");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
}
void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout)
{
if (eloop_replenish_timeout(session_timeout, 0,
ap_handle_session_timer, hapd, sta) == 1) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "setting session timeout "
"to %d seconds", session_timeout);
}
}
@ -471,6 +554,32 @@ void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
}
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
{
#ifdef CONFIG_WNM
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
MAC2STR(sta->addr));
if (sta->hs20_session_info_url == NULL)
return;
wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
sta->hs20_disassoc_timer);
#endif /* CONFIG_WNM */
}
void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
struct sta_info *sta, int warning_time)
{
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
hapd, sta);
}
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
@ -495,13 +604,16 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
accounting_sta_get_id(hapd, sta);
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
__func__, MAC2STR(addr),
hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
/* initialize STA info data */
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
__func__, MAC2STR(addr),
hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
sta->next = hapd->sta_list;
hapd->sta_list = sta;
@ -509,6 +621,8 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
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);
return sta;
}
@ -518,6 +632,10 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (sta->ipaddr)
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
ap_sta_ip6addr_del(hapd, sta);
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
MAC2STR(sta->addr));
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
@ -570,7 +688,8 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_ASSOC;
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@ -608,7 +727,8 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
{
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@ -663,13 +783,6 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->vlan_id == old_vlanid)
return 0;
/*
* During 1x reauth, if the vlan id changes, then remove the old id and
* proceed furthur to add the new one.
*/
if (old_vlanid > 0)
vlan_remove_dynamic(hapd, old_vlanid);
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
iface = sta->ssid->vlan;
@ -677,15 +790,19 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
struct hostapd_vlan *wildcard_vlan = NULL;
vlan = hapd->conf->vlan;
while (vlan) {
if (vlan->vlan_id == sta->vlan_id ||
vlan->vlan_id == VLAN_ID_WILDCARD) {
iface = vlan->ifname;
if (vlan->vlan_id == sta->vlan_id)
break;
}
if (vlan->vlan_id == VLAN_ID_WILDCARD)
wildcard_vlan = vlan;
vlan = vlan->next;
}
if (!vlan)
vlan = wildcard_vlan;
if (vlan)
iface = vlan->ifname;
}
if (sta->vlan_id > 0 && vlan == NULL) {
@ -693,7 +810,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
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) {
@ -702,7 +820,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
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;
@ -756,6 +875,12 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
"entry to vlan_id=%d", sta->vlan_id);
}
done:
/* During 1x reauth, if the vlan id changes, then remove the old id. */
if (old_vlanid > 0)
vlan_remove_dynamic(hapd, old_vlanid);
return ret;
#else /* CONFIG_NO_VLAN */
return 0;
@ -768,9 +893,9 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
struct os_time now, passed;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
struct os_reltime now, passed;
os_get_reltime(&now);
os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
hostapd_logger(hapd, sta->addr,
@ -807,13 +932,21 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
return;
if (sta->sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_time(&sta->sa_query_start);
os_get_reltime(&sta->sa_query_start);
}
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
/*
* We don't really care which ID is used here, so simply
* hardcode this if the mostly theoretical os_get_random()
* failure happens.
*/
trans_id[0] = 0x12;
trans_id[1] = 0x34;
}
timeout = hapd->conf->assoc_sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
@ -849,13 +982,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
const u8 *dev_addr = NULL;
char buf[100];
#ifdef CONFIG_P2P
u8 addr[ETH_ALEN];
u8 ip_addr_buf[4];
#endif /* CONFIG_P2P */
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
if (authorized)
sta->flags |= WLAN_STA_AUTHORIZED;
else
sta->flags &= ~WLAN_STA_AUTHORIZED;
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
if (sta->p2p_ie != NULL &&
@ -863,52 +1003,46 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
dev_addr = addr;
} else
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
if (dev_addr)
os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
#endif /* CONFIG_P2P */
if (authorized) {
if (dev_addr)
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
MACSTR, MAC2STR(sta->addr));
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED MACSTR " p2p_dev_addr="
MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
sta->flags |= WLAN_STA_AUTHORIZED;
} else {
if (dev_addr)
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
MACSTR, MAC2STR(sta->addr));
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
else if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED MACSTR,
MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_AUTHORIZED;
}
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
sta->addr, authorized, dev_addr);
if (authorized) {
char ip_addr[100];
ip_addr[0] = '\0';
#ifdef CONFIG_P2P
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
os_snprintf(ip_addr, sizeof(ip_addr),
" ip_addr=%u.%u.%u.%u",
ip_addr_buf[0], ip_addr_buf[1],
ip_addr_buf[2], ip_addr_buf[3]);
}
#endif /* CONFIG_P2P */
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
buf, ip_addr);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED "%s%s",
buf, ip_addr);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED "%s", buf);
}
}
@ -969,3 +1103,36 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
ap_sta_disassoc_cb_timeout(hapd, sta);
}
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
{
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%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
(flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
""),
(flags & WLAN_STA_SHORT_PREAMBLE ?
"[SHORT_PREAMBLE]" : ""),
(flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
(flags & WLAN_STA_WMM ? "[WMM]" : ""),
(flags & WLAN_STA_MFP ? "[MFP]" : ""),
(flags & WLAN_STA_WPS ? "[WPS]" : ""),
(flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
(flags & WLAN_STA_WDS ? "[WDS]" : ""),
(flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
(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))
res = -1;
return res;
}

View File

@ -9,12 +9,16 @@
#ifndef STA_INFO_H
#define STA_INFO_H
#ifdef CONFIG_MESH
/* needed for mesh_plink_state enum */
#include "common/defs.h"
#endif /* CONFIG_MESH */
#include "list.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
#define WLAN_STA_PS BIT(2)
#define WLAN_STA_TIM BIT(3)
#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
@ -29,6 +33,9 @@
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
#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)
@ -42,6 +49,8 @@ struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
u8 addr[6];
be32 ipaddr;
struct dl_list ip6addr; /* list head for struct ip6addr */
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
@ -50,19 +59,39 @@ struct sta_info {
int supported_rates_len;
u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
#ifdef CONFIG_MESH
enum mesh_plink_state plink_state;
u16 peer_lid;
u16 my_lid;
u16 mpm_close_reason;
int mpm_retries;
u8 my_nonce[32];
u8 peer_nonce[32];
u8 aek[32]; /* SHA256 digest length */
u8 mtk[16];
u8 mgtk[16];
u8 sae_auth_retry;
#endif /* CONFIG_MESH */
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
unsigned int ht40_intolerant_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
unsigned int qos_map_enabled:1;
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;
u8 previous_ap[6];
enum {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE,
STA_DISASSOC_FROM_CLI
} timeout_next;
u16 deauth_reason;
@ -71,12 +100,9 @@ struct sta_info {
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
/* IEEE 802.11f (IAPP) related data */
struct ieee80211_mgmt *last_assoc_req;
u32 acct_session_id_hi;
u32 acct_session_id_lo;
time_t acct_session_start;
struct os_reltime acct_session_start;
int acct_session_started;
int acct_terminate_cause; /* Acct-Terminate-Cause */
int acct_interim_interval; /* Acct-Interim-Interval */
@ -103,6 +129,7 @@ struct sta_info {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
@ -111,7 +138,7 @@ struct sta_info {
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_time sa_query_start;
struct os_reltime sa_query_start;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_INTERWORKING
@ -123,13 +150,25 @@ struct sta_info {
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
u8 remediation_method;
char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
int hs20_disassoc_timer;
struct os_time connected_time;
struct os_reltime connected_time;
#ifdef CONFIG_SAE
enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
u16 sae_send_confirm;
struct sae_data *sae;
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
/* Last Authentication/(Re)Association Request/Action frame sequence
* control */
u16 last_seq_ctrl;
/* Last Authentication/(Re)Association Request/Action frame subtype */
u8 last_subtype;
};
@ -156,14 +195,20 @@ int ap_for_each_sta(struct hostapd_data *hapd,
void *ctx),
void *ctx);
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout);
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
struct sta_info *sta);
void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
struct sta_info *sta, int warning_time);
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
@ -191,4 +236,6 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
#endif /* STA_INFO_H */

View File

@ -68,7 +68,7 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
struct os_time now;
struct os_reltime now;
int ret = 0;
if (addr && local) {
@ -89,8 +89,8 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
}
}
os_get_time(&now);
if (now.sec > hapd->michael_mic_failure + 60) {
os_get_reltime(&now);
if (os_reltime_expired(&now, &hapd->michael_mic_failure, 60)) {
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
@ -99,7 +99,7 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
ret = 1;
}
}
hapd->michael_mic_failure = now.sec;
hapd->michael_mic_failure = now;
return ret;
}

View File

@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -493,8 +487,18 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
vlan->vlan_id);
} else if (tagged_interface) {
os_snprintf(br_name, sizeof(br_name),
"br%s.%d", tagged_interface,
vlan->vlan_id);
} else {
os_snprintf(br_name, sizeof(br_name),
"brvlan%d", vlan->vlan_id);
}
if (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
@ -550,8 +554,18 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
vlan->vlan_id);
} else if (tagged_interface) {
os_snprintf(br_name, sizeof(br_name),
"br%s.%d", tagged_interface,
vlan->vlan_id);
} else {
os_snprintf(br_name, sizeof(br_name),
"brvlan%d", vlan->vlan_id);
}
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
@ -603,6 +617,7 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
struct ifinfomsg *ifi;
int attrlen, nlmsg_len, rta_len;
struct rtattr *attr;
char ifname[IFNAMSIZ + 1];
if (len < sizeof(*ifi))
return;
@ -617,29 +632,39 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
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;
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);
}
@ -663,7 +688,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
}
h = (struct nlmsghdr *) buf;
while (left >= (int) sizeof(*h)) {
while (NLMSG_OK(h, left)) {
int len, plen;
len = h->nlmsg_len;
@ -684,9 +709,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
break;
}
len = NLMSG_ALIGN(len);
left -= len;
h = (struct nlmsghdr *) ((char *) h + len);
h = NLMSG_NEXT(h, left);
}
if (left > 0) {
@ -837,6 +860,24 @@ int vlan_init(struct hostapd_data *hapd)
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
!hapd->conf->vlan) {
/* dynamic vlans enabled but no (or empty) vlan_file given */
struct hostapd_vlan *vlan;
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while assigning "
"VLAN interfaces");
return -1;
}
vlan->vlan_id = VLAN_ID_WILDCARD;
os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
hapd->conf->iface);
vlan->next = hapd->conf->vlan;
hapd->conf->vlan = vlan;
}
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
return -1;
@ -850,6 +891,7 @@ void vlan_deinit(struct hostapd_data *hapd)
#ifdef CONFIG_FULL_DYNAMIC_VLAN
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
hapd->full_dynamic_vlan = NULL;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
@ -858,7 +900,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
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 ||
@ -871,28 +913,24 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
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;
@ -902,6 +940,8 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
ifconfig_up(n->ifname);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
free_ifname:
os_free(ifname);
return n;
}

View File

@ -3,14 +3,8 @@
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef VLAN_INIT_H

View File

@ -4,14 +4,8 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -157,7 +151,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
len = ((u8 *) (t + 1)) - buf;
if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
perror("wmm_send_action: send");
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}

View File

@ -3,14 +3,8 @@
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WME_H

View File

@ -1,6 +1,6 @@
/*
* hostapd - WNM
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -9,7 +9,9 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
@ -72,7 +74,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wnmsleep_ie.len = wnmsleep_ie_len - 2;
wnmsleep_ie.action_type = action_type;
wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
wnmsleep_ie.intval = intval;
wnmsleep_ie.intval = host_to_le16(intval);
/* TFS IE(s) */
wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
@ -154,6 +156,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
sta->flags |= WLAN_STA_WNM_SLEEP_MODE;
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
addr, NULL, NULL);
wpa_set_wnmsleep(sta->wpa_sm, 1);
@ -167,6 +170,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
wnmsleep_ie.status ==
WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
@ -233,7 +237,7 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
wnmsleep_ie->action_type,
wnmsleep_ie->intval);
le_to_host16(wnmsleep_ie->intval));
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
/* clear the tfs after sending the resp frame */
@ -243,29 +247,350 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
}
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
struct rx_action *action)
static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
const u8 *addr,
u8 dialog_token,
const char *url)
{
if (action->len < 1 || action->data == NULL)
struct ieee80211_mgmt *mgmt;
size_t url_len, len;
u8 *pos;
int res;
if (url)
url_len = os_strlen(url);
else
url_len = 0;
mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
if (mgmt == NULL)
return -1;
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
mgmt->u.action.u.bss_tm_req.req_mode = 0;
mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
pos = mgmt->u.action.u.bss_tm_req.variable;
if (url) {
*pos++ += url_len;
os_memcpy(pos, url, url_len);
pos += url_len;
}
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
"validity_interval=%u",
MAC2STR(addr), dialog_token,
mgmt->u.action.u.bss_tm_req.req_mode,
le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer),
mgmt->u.action.u.bss_tm_req.validity_interval);
len = pos - &mgmt->u.action.category;
res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
mgmt->da, &mgmt->u.action.category, len);
os_free(mgmt);
return res;
}
static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm,
size_t len)
{
u8 dialog_token, reason;
const u8 *pos, *end;
if (len < 2) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
MACSTR, MAC2STR(addr));
return;
}
pos = frm;
end = pos + len;
dialog_token = *pos++;
reason = *pos++;
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from "
MACSTR " dialog_token=%u reason=%u",
MAC2STR(addr), dialog_token, reason);
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
}
static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm,
size_t len)
{
u8 dialog_token, status_code, bss_termination_delay;
const u8 *pos, *end;
if (len < 3) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
MACSTR, MAC2STR(addr));
return;
}
pos = frm;
end = pos + len;
dialog_token = *pos++;
status_code = *pos++;
bss_termination_delay = *pos++;
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from "
MACSTR " dialog_token=%u status_code=%u "
"bss_termination_delay=%u", MAC2STR(addr), dialog_token,
status_code, bss_termination_delay);
if (status_code == WNM_BSS_TM_ACCEPT) {
if (end - pos < ETH_ALEN) {
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
return;
}
wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
MAC2STR(pos));
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
" status_code=%u bss_termination_delay=%u target_bssid="
MACSTR,
MAC2STR(addr), status_code, bss_termination_delay,
MAC2STR(pos));
pos += ETH_ALEN;
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
" status_code=%u bss_termination_delay=%u",
MAC2STR(addr), status_code, bss_termination_delay);
}
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
u8 action;
const u8 *payload;
size_t plen;
if (len < IEEE80211_HDRLEN + 2)
return -1;
switch (action->data[0]) {
payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
action = *payload++;
plen = len - IEEE80211_HDRLEN - 2;
switch (action) {
case WNM_BSS_TRANS_MGMT_QUERY:
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
/* TODO */
return -1;
ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
plen);
return 0;
case WNM_BSS_TRANS_MGMT_RESP:
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
"Response");
/* TODO */
return -1;
ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
plen);
return 0;
case WNM_SLEEP_MODE_REQ:
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
action->len - 1);
ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
action->data[0], MAC2STR(action->sa));
action, MAC2STR(mgmt->sa));
return -1;
}
int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, int disassoc_timer)
{
u8 buf[1000], *pos;
struct ieee80211_mgmt *mgmt;
os_memset(buf, 0, sizeof(buf));
mgmt = (struct ieee80211_mgmt *) buf;
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
mgmt->u.action.u.bss_tm_req.req_mode =
WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
mgmt->u.action.u.bss_tm_req.disassoc_timer =
host_to_le16(disassoc_timer);
mgmt->u.action.u.bss_tm_req.validity_interval = 0;
pos = mgmt->u.action.u.bss_tm_req.variable;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
}
return 0;
}
static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
int disassoc_timer)
{
int timeout, beacon_int;
/*
* Prevent STA from reconnecting using cached PMKSA to force
* full authentication with the authentication server (which may
* decide to reject the connection),
*/
wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
beacon_int = hapd->iconf->beacon_int;
if (beacon_int < 1)
beacon_int = 100; /* best guess */
/* Calculate timeout in ms based on beacon_int in TU */
timeout = disassoc_timer * beacon_int * 128 / 125;
wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
" set to %d ms", MAC2STR(sta->addr), timeout);
sta->timeout_next = STA_DISASSOC_FROM_CLI;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(timeout / 1000,
timeout % 1000 * 1000,
ap_handle_timer, hapd, sta);
}
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer)
{
u8 buf[1000], *pos;
struct ieee80211_mgmt *mgmt;
size_t url_len;
os_memset(buf, 0, sizeof(buf));
mgmt = (struct ieee80211_mgmt *) buf;
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
mgmt->u.action.u.bss_tm_req.req_mode =
WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
mgmt->u.action.u.bss_tm_req.disassoc_timer =
host_to_le16(disassoc_timer);
mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
pos = mgmt->u.action.u.bss_tm_req.variable;
/* Session Information URL */
url_len = os_strlen(url);
if (url_len > 255)
return -1;
*pos++ = url_len;
os_memcpy(pos, url, url_len);
pos += url_len;
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
}
if (disassoc_timer) {
/* send disassociation frame after time-out */
set_disassoc_timer(hapd, sta, disassoc_timer);
}
return 0;
}
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
const u8 *nei_rep, size_t nei_rep_len)
{
u8 *buf, *pos;
struct ieee80211_mgmt *mgmt;
size_t url_len;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
buf = os_zalloc(1000 + nei_rep_len);
if (buf == NULL)
return -1;
mgmt = (struct ieee80211_mgmt *) buf;
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
mgmt->u.action.u.bss_tm_req.dialog_token = 1;
mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
mgmt->u.action.u.bss_tm_req.disassoc_timer =
host_to_le16(disassoc_timer);
mgmt->u.action.u.bss_tm_req.validity_interval = valid_int;
pos = mgmt->u.action.u.bss_tm_req.variable;
if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) &&
bss_term_dur) {
os_memcpy(pos, bss_term_dur, 12);
pos += 12;
}
if (url) {
/* Session Information URL */
url_len = os_strlen(url);
if (url_len > 255) {
os_free(buf);
return -1;
}
*pos++ = url_len;
os_memcpy(pos, url, url_len);
pos += url_len;
}
if (nei_rep) {
os_memcpy(pos, nei_rep, nei_rep_len);
pos += nei_rep_len;
}
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
return -1;
}
os_free(buf);
if (disassoc_timer) {
/* send disassociation frame after time-out */
set_disassoc_timer(hapd, sta, disassoc_timer);
}
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* IEEE 802.11v WNM related functions and structures
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
* Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -9,9 +9,18 @@
#ifndef WNM_AP_H
#define WNM_AP_H
struct rx_action;
struct sta_info;
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
struct rx_action *action);
const struct ieee80211_mgmt *mgmt, size_t len);
int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, int disassoc_timer);
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer);
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
const u8 *bss_term_dur, const char *url,
const u8 *nei_rep, size_t nei_rep_len);
#endif /* WNM_AP_H */

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ struct ft_rrb_frame {
#define FT_R0KH_R1KH_PULL_DATA_LEN 44
#define FT_R0KH_R1KH_RESP_DATA_LEN 76
#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
struct ft_r0kh_r1kh_pull_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
@ -49,7 +50,7 @@ struct ft_r0kh_r1kh_pull_frame {
le16 data_length; /* little endian length of data (44) */
u8 ap_address[ETH_ALEN];
u8 nonce[16];
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 r1kh_id[FT_R1KH_ID_LEN];
u8 s1kh_id[ETH_ALEN];
@ -63,7 +64,7 @@ struct ft_r0kh_r1kh_resp_frame {
le16 data_length; /* little endian length of data (76) */
u8 ap_address[ETH_ALEN];
u8 nonce[16]; /* copied from pull */
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
u8 pmk_r1[PMK_LEN];
@ -142,6 +143,7 @@ struct wpa_auth_config {
int tx_status;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
#define SSID_LEN 32
@ -160,6 +162,15 @@ struct wpa_auth_config {
#endif /* CONFIG_IEEE80211R */
int disable_gtk;
int ap_mlme;
#ifdef CONFIG_TESTING_OPTIONS
double corrupt_gtk_rekey_mic_probability;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
u8 ip_addr_start[4];
u8 ip_addr_end[4];
#endif /* CONFIG_P2P */
};
typedef enum {
@ -181,7 +192,8 @@ struct wpa_auth_callbacks {
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
const u8 *prev_psk);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key, size_t key_len);
@ -199,8 +211,11 @@ struct wpa_auth_callbacks {
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_MESH
int (*start_ampe)(void *ctx, const u8 *sta_addr);
#endif /* CONFIG_MESH */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
@ -222,9 +237,13 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *p2p_dev_addr);
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm);
void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
@ -260,6 +279,10 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
@ -288,5 +311,13 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
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 */

View File

@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
* Copyright (c) 2004-2009, 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.
@ -9,6 +9,8 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
@ -22,6 +24,12 @@
#ifdef CONFIG_IEEE80211R
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
u16 status, const u8 *resp_ies,
size_t resp_ies_len);
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
@ -57,7 +65,7 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
u8 *tspec_ie, size_t tspec_ielen)
{
if (wpa_auth->cb.add_tspec == NULL) {
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
return -1;
}
return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
@ -228,8 +236,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
r0 = cache->pmk_r0;
while (r0) {
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
== 0) {
os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
WPA_PMK_NAME_LEN) == 0) {
os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
if (pairwise)
*pairwise = r0->pairwise;
@ -278,8 +286,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
r1 = cache->pmk_r1;
while (r1) {
if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
== 0) {
os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
WPA_PMK_NAME_LEN) == 0) {
os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
if (pairwise)
*pairwise = r1->pairwise;
@ -293,22 +301,26 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
}
static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
const u8 *s1kh_id, const u8 *r0kh_id,
size_t r0kh_id_len, const u8 *pmk_r0_name)
static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
const u8 *pmk_r0_name)
{
struct ft_remote_r0kh *r0kh;
struct ft_r0kh_r1kh_pull_frame frame, f;
r0kh = wpa_auth->conf.r0kh_list;
r0kh = sm->wpa_auth->conf.r0kh_list;
while (r0kh) {
if (r0kh->id_len == r0kh_id_len &&
os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
if (r0kh->id_len == sm->r0kh_id_len &&
os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
0)
break;
r0kh = r0kh->next;
}
if (r0kh == NULL)
if (r0kh == NULL) {
wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
"address " MACSTR, MAC2STR(r0kh->addr));
@ -317,31 +329,40 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
os_memcpy(frame.ap_address, sm->wpa_auth->addr, ETH_ALEN);
/* aes_wrap() does not support inplace encryption, so use a temporary
* buffer for the data. */
if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
"nonce");
return -1;
}
os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
FT_R0KH_R1KH_PULL_NONCE_LEN);
os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
os_memset(f.pad, 0, sizeof(f.pad));
if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
if (aes_wrap(r0kh->key, sizeof(r0kh->key),
(FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
f.nonce, frame.nonce) < 0)
return -1;
wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
wpabuf_free(sm->ft_pending_req_ies);
sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
if (sm->ft_pending_req_ies == NULL)
return -1;
wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
return 0;
}
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk, size_t ptk_len)
struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
@ -353,7 +374,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
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");
@ -375,13 +395,9 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
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);
}
@ -416,7 +432,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len = 8 - pad_len;
if (key_len + pad_len < 16)
pad_len += 8;
if (pad_len) {
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
@ -440,7 +456,8 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
subelem + 13)) {
os_free(subelem);
return NULL;
}
@ -472,7 +489,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
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;
@ -569,8 +586,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
else {
/* TSPEC accepted; include updated TSPEC in
* response */
rdie->descr_count = 1;
pos += sizeof(*tspec);
rdie->descr_count = 1;
pos += sizeof(*tspec);
}
return pos;
}
@ -632,8 +649,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
conf = &sm->wpa_auth->conf;
if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return pos;
end = pos + max_len;
@ -725,7 +741,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
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,
@ -769,7 +786,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
* 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) */
@ -777,7 +794,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
}
static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
u8 **resp_ies, size_t *resp_ies_len)
{
@ -787,7 +804,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
size_t buflen, ptk_len;
size_t buflen;
int ret;
u8 *pos, *end;
int pairwise;
@ -848,19 +865,13 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
&pairwise) < 0) {
if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
wpa_printf(MSG_DEBUG, "FT: Did not have matching "
"PMK-R1 and unknown R0KH-ID");
return WLAN_STATUS_INVALID_PMKID;
}
/*
* TODO: Should return "status pending" (and the caller should
* not send out response now). The real response will be sent
* once the response from R0KH is received.
*/
return WLAN_STATUS_INVALID_PMKID;
return -1; /* Status pending */
}
wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
@ -878,15 +889,14 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
ptk_len = 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;
wpa_ft_install_ptk(sm);
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
@ -940,6 +950,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 status;
u8 *resp_ies;
size_t resp_ies_len;
int res;
if (sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
@ -950,8 +961,16 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
" BSSID=" MACSTR " transaction=%d",
MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
&resp_ies_len);
sm->ft_pending_cb = cb;
sm->ft_pending_cb_ctx = ctx;
sm->ft_pending_auth_transaction = auth_transaction;
res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
&resp_ies_len);
if (res < 0) {
wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
return;
}
status = res;
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
" auth_transaction=%d status=%d",
@ -969,7 +988,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
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)
@ -992,8 +1012,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_PMKID;
}
if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
{
if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)
!= 0) {
wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
"with the PMKR1Name derived from auth request");
return WLAN_STATUS_INVALID_PMKID;
@ -1039,7 +1059,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
{
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@ -1054,8 +1075,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return -1;
}
if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
@ -1066,7 +1087,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.rsn_pmkid == NULL ||
os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
{
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@ -1082,7 +1104,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
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,
@ -1092,12 +1115,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (os_memcmp(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",
@ -1166,6 +1190,8 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
/* RRB - Forward action frame to the target AP */
frame = os_malloc(sizeof(*frame) + len);
if (frame == NULL)
return -1;
frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame->packet_type = FT_PACKET_REQUEST;
frame->action_length = host_to_le16(len);
@ -1180,15 +1206,27 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
}
static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len)
{
struct wpa_state_machine *sm = ctx;
wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
MAC2STR(sm->addr));
wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
WLAN_STATUS_SUCCESS, ies, ies_len);
}
static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
const u8 *current_ap, const u8 *sta_addr,
const u8 *body, size_t len)
{
struct wpa_state_machine *sm;
u16 status;
u8 *resp_ies, *pos;
size_t resp_ies_len, rlen;
struct ft_rrb_frame *frame;
u8 *resp_ies;
size_t resp_ies_len;
int res;
sm = wpa_ft_add_sta(wpa_auth, sta_addr);
if (sm == NULL) {
@ -1199,8 +1237,33 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
&resp_ies_len);
sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
sm->ft_pending_cb_ctx = sm;
os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
&resp_ies_len);
if (res < 0) {
wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
return 0;
}
status = res;
res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
resp_ies, resp_ies_len);
os_free(resp_ies);
return res;
}
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
u16 status, const u8 *resp_ies,
size_t resp_ies_len)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
size_t rlen;
struct ft_rrb_frame *frame;
u8 *pos;
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
" CurrentAP=" MACSTR " status=%d",
@ -1216,6 +1279,8 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
frame = os_malloc(sizeof(*frame) + rlen);
if (frame == NULL)
return -1;
frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
frame->packet_type = FT_PACKET_RESPONSE;
frame->action_length = host_to_le16(rlen);
@ -1229,10 +1294,8 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
pos += ETH_ALEN;
WPA_PUT_LE16(pos, status);
pos += 2;
if (resp_ies) {
if (resp_ies)
os_memcpy(pos, resp_ies, resp_ies_len);
os_free(resp_ies);
}
wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
sizeof(*frame) + rlen);
@ -1246,7 +1309,9 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
const u8 *data, size_t data_len)
{
struct ft_r0kh_r1kh_pull_frame *frame, f;
struct ft_r0kh_r1kh_pull_frame f;
const u8 *crypt;
u8 *plain;
struct ft_remote_r1kh *r1kh;
struct ft_r0kh_r1kh_resp_frame resp, r;
u8 pmk_r0[PMK_LEN];
@ -1254,7 +1319,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
if (data_len < sizeof(*frame))
if (data_len < sizeof(f))
return -1;
r1kh = wpa_auth->conf.r1kh_list;
@ -1270,11 +1335,14 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
return -1;
}
frame = (struct ft_r0kh_r1kh_pull_frame *) data;
crypt = data + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
os_memset(&f, 0, sizeof(f));
plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
frame->nonce, f.nonce) < 0) {
if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"request from " MACSTR, MAC2STR(src_addr));
return -1;
@ -1284,7 +1352,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
f.nonce, sizeof(f.nonce));
wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
f.pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
os_memset(&resp, 0, sizeof(resp));
@ -1311,8 +1379,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
WPA_PMK_NAME_LEN);
r.pairwise = host_to_le16(pairwise);
os_memset(r.pad, 0, sizeof(r.pad));
if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
if (aes_wrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
r.nonce, resp.nonce) < 0) {
os_memset(pmk_r0, 0, PMK_LEN);
return -1;
@ -1326,17 +1396,64 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
}
static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_state_machine *sm = eloop_ctx;
int res;
u8 *resp_ies;
size_t resp_ies_len;
u16 status;
res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
wpabuf_len(sm->ft_pending_req_ies),
&resp_ies, &resp_ies_len);
wpabuf_free(sm->ft_pending_req_ies);
sm->ft_pending_req_ies = NULL;
if (res < 0)
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
status = res;
wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
" - status %u", MAC2STR(sm->addr), status);
sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
sm->ft_pending_auth_transaction + 1, status,
resp_ies, resp_ies_len);
os_free(resp_ies);
}
static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
{
struct ft_r0kh_r1kh_resp_frame *frame = ctx;
if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
return 0;
if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
return 0;
if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
return 0;
wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
MACSTR " - process from timeout", MAC2STR(sm->addr));
eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
return 1;
}
static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
const u8 *data, size_t data_len)
{
struct ft_r0kh_r1kh_resp_frame *frame, f;
struct ft_r0kh_r1kh_resp_frame f;
const u8 *crypt;
u8 *plain;
struct ft_remote_r0kh *r0kh;
int pairwise;
int pairwise, res;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
if (data_len < sizeof(*frame))
if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@ -1352,31 +1469,30 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
return -1;
}
frame = (struct ft_r0kh_r1kh_resp_frame *) data;
crypt = data + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
os_memset(&f, 0, sizeof(f));
plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
frame->nonce, f.nonce) < 0) {
if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
(FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"response from " MACSTR, MAC2STR(src_addr));
return -1;
}
if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
!= 0) {
if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
"matching R1KH-ID");
return -1;
}
/* TODO: verify that <nonce,s1kh_id> matches with a pending request
* and call this requests callback function to finish request
* processing */
pairwise = le_to_host16(f.pairwise);
wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
f.nonce, sizeof(f.nonce));
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
MACSTR " pairwise=0x%x",
MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
@ -1384,11 +1500,13 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
f.pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
pairwise);
res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
pairwise);
wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
os_memset(f.pmk_r1, 0, PMK_LEN);
return 0;
return res ? 0 : -1;
}
@ -1396,7 +1514,9 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
const u8 *data, size_t data_len)
{
struct ft_r0kh_r1kh_push_frame *frame, f;
struct ft_r0kh_r1kh_push_frame f;
const u8 *crypt;
u8 *plain;
struct ft_remote_r0kh *r0kh;
struct os_time now;
os_time_t tsend;
@ -1404,7 +1524,7 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
if (data_len < sizeof(*frame))
if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@ -1420,11 +1540,15 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
return -1;
}
frame = (struct ft_r0kh_r1kh_push_frame *) data;
crypt = data + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp);
os_memset(&f, 0, sizeof(f));
plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
timestamp);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
frame->timestamp, f.timestamp) < 0) {
if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
MACSTR, MAC2STR(src_addr));
return -1;
@ -1440,8 +1564,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
return -1;
}
if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
!= 0) {
if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
"R1KH-ID (received " MACSTR " own " MACSTR ")",
MAC2STR(f.r1kh_id),
@ -1582,6 +1706,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
if (end > pos) {
wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
pos, end - pos);
}
return 0;
}
@ -1593,6 +1722,8 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
{
struct ft_r0kh_r1kh_push_frame frame, f;
struct os_time now;
const u8 *plain;
u8 *crypt;
os_memset(&frame, 0, sizeof(frame));
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
@ -1614,8 +1745,14 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
os_get_time(&now);
WPA_PUT_LE32(f.timestamp, now.sec);
f.pairwise = host_to_le16(pairwise);
if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
f.timestamp, frame.timestamp) < 0)
os_memset(f.pad, 0, sizeof(f.pad));
plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
timestamp);
crypt = ((u8 *) &frame) + offsetof(struct ft_r0kh_r1kh_push_frame,
timestamp);
if (aes_wrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
plain, crypt) < 0)
return;
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));

View File

@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -10,11 +10,11 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "l2_packet/l2_packet.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "preauth_auth.h"
@ -27,6 +27,7 @@
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
os_memset(wconf, 0, sizeof(*wconf));
@ -48,6 +49,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
@ -72,7 +74,30 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
if (conf->osen) {
wconf->disable_gtk = 1;
wconf->wpa = WPA_PROTO_OSEN;
wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
wconf->wpa_pairwise = 0;
wconf->wpa_group = WPA_CIPHER_CCMP;
wconf->rsn_pairwise = WPA_CIPHER_CCMP;
wconf->rsn_preauth = 0;
wconf->disable_pmksa_caching = 1;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = 1;
#endif /* CONFIG_IEEE80211W */
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
wconf->corrupt_gtk_rekey_mic_probability =
iconf->corrupt_gtk_rekey_mic_probability;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4);
os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4);
os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4);
#endif /* CONFIG_P2P */
}
@ -180,11 +205,22 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *p2p_dev_addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
const u8 *psk;
#ifdef CONFIG_SAE
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
if (!sta->sae || prev_psk)
return NULL;
return sta->sae->pmk;
}
#endif /* CONFIG_SAE */
psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
@ -213,12 +249,17 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
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;
@ -263,6 +304,21 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
struct sta_info *sta;
u32 flags = 0;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->ext_eapol_frame_io) {
size_t hex_len = 2 * data_len + 1;
char *hex = os_malloc(hex_len);
if (hex == NULL)
return -1;
wpa_snprintf_hex(hex, hex_len, data, data_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
MAC2STR(addr), hex);
os_free(hex);
return 0;
}
#endif /* CONFIG_TESTING_OPTIONS */
sta = ap_get_sta(hapd, addr);
if (sta)
flags = hostapd_sta_flags_to_drv(sta->flags);
@ -368,6 +424,21 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
struct l2_ethhdr *buf;
int ret;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
size_t hex_len = 2 * data_len + 1;
char *hex = os_malloc(hex_len);
if (hex == NULL)
return -1;
wpa_snprintf_hex(hex, hex_len, data, data_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
MAC2STR(dst), hex);
os_free(hex);
return 0;
}
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211R
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@ -455,7 +526,7 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
return sta->wpa_sm;
}
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL);
if (sta->wpa_sm == NULL) {
ap_free_sta(hapd, sta);
return NULL;
@ -498,7 +569,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
const u8 *wpa_ie;
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, &_conf);
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
@ -572,7 +643,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
void hostapd_reconfig_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config wpa_auth_conf;
hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf);
wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
}
@ -601,5 +672,6 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
l2_packet_deinit(hapd->l2);
hapd->l2 = NULL;
#endif /* CONFIG_IEEE80211R */
}

View File

@ -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.
@ -26,6 +26,7 @@ struct wpa_state_machine {
struct wpa_group *group;
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
@ -57,6 +58,8 @@ struct wpa_state_machine {
Boolean GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 PMK[PMK_LEN];
struct wpa_ptk PTK;
Boolean PTK_valid;
@ -83,6 +86,7 @@ struct wpa_state_machine {
unsigned int mgmt_frame_prot:1;
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@ -117,9 +121,22 @@ struct wpa_state_machine {
u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
* message 2/4 */
u8 *assoc_resp_ftie;
void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len);
void *ft_pending_cb_ctx;
struct wpabuf *ft_pending_req_ies;
u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
u8 ft_pending_auth_transaction;
u8 ft_pending_current_ap[ETH_ALEN];
#endif /* CONFIG_IEEE80211R */
int pending_1_of_4_timeout;
#ifdef CONFIG_P2P
u8 ip_addr[4];
#endif /* CONFIG_P2P */
};
@ -138,7 +155,8 @@ struct wpa_group {
enum {
WPA_GROUP_GTK_INIT = 0,
WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE,
WPA_GROUP_FATAL_FAILURE
} wpa_group_state;
u8 GMK[WPA_GMK_LEN];
@ -148,7 +166,7 @@ struct wpa_group {
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN];
u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
};
@ -183,6 +201,10 @@ struct wpa_authenticator {
struct rsn_pmksa_cache *pmksa;
struct wpa_ft_pmk_cache *ft_pmk_cache;
#ifdef CONFIG_P2P
struct bitfield *ip_pool;
#endif /* CONFIG_P2P */
};
@ -208,11 +230,14 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
struct wpa_state_machine *sm,
const u8 *key_data, size_t key_data_len);
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
const u8 *key_data, size_t key_data_len);
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
const u8 *key_data, size_t key_data_len);
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
@ -223,7 +248,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
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);

View File

@ -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.
@ -200,6 +200,16 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_SAE */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
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) {
@ -261,7 +271,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
switch (conf->group_mgmt_cipher) {
case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
break;
case WPA_CIPHER_BIP_GMAC_128:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
break;
case WPA_CIPHER_BIP_GMAC_256:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
break;
case WPA_CIPHER_BIP_CMAC_256:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
break;
default:
wpa_printf(MSG_DEBUG,
"Invalid group management cipher (0x%x)",
conf->group_mgmt_cipher);
return -1;
}
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
@ -295,6 +323,55 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
u16 capab;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
len = eid++; /* to be filled */
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_OSEN_OUI_TYPE;
/* Group Data Cipher Suite */
RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
eid += RSN_SELECTOR_LEN;
/* Pairwise Cipher Suite Count and List */
WPA_PUT_LE16(eid, 1);
eid += 2;
RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
eid += RSN_SELECTOR_LEN;
/* AKM Suite Count and List */
WPA_PUT_LE16(eid, 1);
eid += 2;
RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
eid += RSN_SELECTOR_LEN;
/* RSN Capabilities */
capab = 0;
if (conf->wmm_enabled) {
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16(eid, capab);
eid += 2;
*len = eid - len - 1;
return eid;
}
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
@ -302,6 +379,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos = buf;
if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
pos = wpa_write_osen(&wpa_auth->conf, pos);
}
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
@ -407,6 +487,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
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
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
@ -485,6 +569,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
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
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@ -534,7 +622,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
{
wpa_printf(MSG_DEBUG, "Unsupported management group "
"cipher %d", data.mgmt_group_cipher);
return WPA_INVALID_MGMT_GROUP_CIPHER;
@ -564,12 +653,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_IEEE80211R */
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
else if (ciphers & WPA_CIPHER_GCMP)
sm->pairwise = WPA_CIPHER_GCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
@ -607,7 +693,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
break;
}
}
if (sm->pmksa) {
if (sm->pmksa && pmkid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",
@ -629,6 +715,36 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#ifdef CONFIG_HS20
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len)
{
if (wpa_auth == NULL || sm == NULL)
return -1;
/* TODO: parse OSEN element */
sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
sm->mgmt_frame_prot = 1;
sm->pairwise = WPA_CIPHER_CCMP;
sm->wpa = WPA_VERSION_WPA2;
if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(osen_ie_len);
if (sm->wpa_ie == NULL)
return -1;
}
os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
sm->wpa_ie_len = osen_ie_len;
return 0;
}
#endif /* CONFIG_HS20 */
/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
@ -651,6 +767,12 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
ie->osen = pos;
ie->osen_len = pos[1] + 2;
return 0;
}
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
@ -711,6 +833,25 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
return 0;
}
if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
wpa_hexdump(MSG_DEBUG,
"WPA: IP Address Allocation in EAPOL-Key",
ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
return 0;
}
#endif /* CONFIG_P2P */
return 0;
}

View File

@ -39,6 +39,13 @@ struct wpa_eapol_ie_parse {
const u8 *ftie;
size_t ftie_len;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_P2P
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
const u8 *osen;
size_t osen_len;
};
int wpa_parse_kde_ies(const u8 *buf, size_t len,

Some files were not shown because too many files have changed in this diff Show More