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:
commit
842f4520d0
143
contrib/wpa/CONTRIBUTIONS
Normal file
143
contrib/wpa/CONTRIBUTIONS
Normal 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.
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
17
contrib/wpa/hostapd/hapd_module_tests.c
Normal file
17
contrib/wpa/hostapd/hapd_module_tests.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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
342
contrib/wpa/hostapd/wps-ap-nfc.py
Executable 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()
|
81
contrib/wpa/hs20/client/Android.mk
Normal file
81
contrib/wpa/hs20/client/Android.mk
Normal 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)
|
||||
|
||||
########################
|
94
contrib/wpa/hs20/client/Makefile
Normal file
94
contrib/wpa/hs20/client/Makefile
Normal 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)
|
47
contrib/wpa/hs20/client/devdetail.xml
Normal file
47
contrib/wpa/hs20/client/devdetail.xml
Normal 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>
|
7
contrib/wpa/hs20/client/devinfo.xml
Normal file
7
contrib/wpa/hs20/client/devinfo.xml
Normal 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>
|
715
contrib/wpa/hs20/client/est.c
Normal file
715
contrib/wpa/hs20/client/est.c
Normal 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;
|
||||
}
|
1392
contrib/wpa/hs20/client/oma_dm_client.c
Normal file
1392
contrib/wpa/hs20/client/oma_dm_client.c
Normal file
File diff suppressed because it is too large
Load Diff
3227
contrib/wpa/hs20/client/osu_client.c
Normal file
3227
contrib/wpa/hs20/client/osu_client.c
Normal file
File diff suppressed because it is too large
Load Diff
118
contrib/wpa/hs20/client/osu_client.h
Normal file
118
contrib/wpa/hs20/client/osu_client.h
Normal 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 */
|
995
contrib/wpa/hs20/client/spp_client.c
Normal file
995
contrib/wpa/hs20/client/spp_client.c
Normal 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;
|
||||
}
|
@ -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:
|
@ -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:
|
@ -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:
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
949
contrib/wpa/src/ap/acs.c
Normal 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(¶ms, 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], ¶ms) < 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
27
contrib/wpa/src/ap/acs.h
Normal 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 */
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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, ¶ms);
|
||||
@ -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(¶ms, 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, ¶ms);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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, ¶ms)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
|
||||
|
@ -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(¶ms, 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, ¶ms))
|
||||
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, ¶ms) < 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, ¶ms);
|
||||
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(¶ms);
|
||||
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 */
|
||||
|
@ -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 */
|
||||
|
65
contrib/wpa/src/ap/bss_load.c
Normal file
65
contrib/wpa/src/ap/bss_load.c
Normal 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);
|
||||
}
|
17
contrib/wpa/src/ap/bss_load.h
Normal file
17
contrib/wpa/src/ap/bss_load.h
Normal 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 */
|
@ -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);
|
||||
}
|
||||
|
@ -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
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
30
contrib/wpa/src/ap/dfs.h
Normal 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 */
|
178
contrib/wpa/src/ap/dhcp_snoop.c
Normal file
178
contrib/wpa/src/ap/dhcp_snoop.c
Normal 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);
|
||||
}
|
30
contrib/wpa/src/ap/dhcp_snoop.h
Normal file
30
contrib/wpa/src/ap/dhcp_snoop.h
Normal 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 */
|
@ -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 @@ skip_wpa_check:
|
||||
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 @@ skip_wpa_check:
|
||||
|
||||
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 @@ fail:
|
||||
|
||||
|
||||
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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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(¶ms, 0, sizeof(params));
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
|
||||
ieee80211n_scan_channels_2g4(iface, ¶ms);
|
||||
else
|
||||
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||
|
||||
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||
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(¶ms, 0, sizeof(params));
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
|
||||
ieee80211n_scan_channels_2g4(iface, ¶ms);
|
||||
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to request a scan of "
|
||||
"neighboring BSSes");
|
||||
os_free(params.freqs);
|
||||
else
|
||||
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||
|
||||
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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);
|
||||
|
171
contrib/wpa/src/ap/ndisc_snoop.c
Normal file
171
contrib/wpa/src/ap/ndisc_snoop.c
Normal 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);
|
||||
}
|
36
contrib/wpa/src/ap/ndisc_snoop.h
Normal file
36
contrib/wpa/src/ap/ndisc_snoop.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user