MFV r341618:
Update wpa 2.6 --> 2.7.
This commit is contained in:
commit
b53b242388
@ -140,7 +140,7 @@ The license terms used for hostap.git files
|
||||
|
||||
Modified BSD license (no advertisement clause):
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
|
@ -1,5 +1,60 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2018-12-02 - v2.7
|
||||
* fixed WPA packet number reuse with replayed messages and key
|
||||
reinstallation
|
||||
[http://w1.fi/security/2017-1/] (CVE-2017-13082)
|
||||
* added support for FILS (IEEE 802.11ai) shared key authentication
|
||||
* added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
|
||||
and transition mode defined by WFA)
|
||||
* added support for DPP (Wi-Fi Device Provisioning Protocol)
|
||||
* FT:
|
||||
- added local generation of PMK-R0/PMK-R1 for FT-PSK
|
||||
(ft_psk_generate_local=1)
|
||||
- replaced inter-AP protocol with a cleaner design that is more
|
||||
easily extensible; this breaks backward compatibility and requires
|
||||
all APs in the ESS to be updated at the same time to maintain FT
|
||||
functionality
|
||||
- added support for wildcard R0KH/R1KH
|
||||
- replaced r0_key_lifetime (minutes) parameter with
|
||||
ft_r0_key_lifetime (seconds)
|
||||
- fixed wpa_psk_file use for FT-PSK
|
||||
- fixed FT-SAE PMKID matching
|
||||
- added expiration to PMK-R0 and PMK-R1 cache
|
||||
- added IEEE VLAN support (including tagged VLANs)
|
||||
- added support for SHA384 based AKM
|
||||
* SAE
|
||||
- fixed some PMKSA caching cases with SAE
|
||||
- added support for configuring SAE password separately of the
|
||||
WPA2 PSK/passphrase
|
||||
- added option to require MFP for SAE associations
|
||||
(sae_require_pmf=1)
|
||||
- fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
|
||||
for SAE;
|
||||
note: this is not backwards compatible, i.e., both the AP and
|
||||
station side implementations will need to be update at the same
|
||||
time to maintain interoperability
|
||||
- added support for Password Identifier
|
||||
* hostapd_cli: added support for command history and completion
|
||||
* added support for requesting beacon report
|
||||
* large number of other fixes, cleanup, and extensions
|
||||
* added option to configure EAPOL-Key retry limits
|
||||
(wpa_group_update_count and wpa_pairwise_update_count)
|
||||
* removed all PeerKey functionality
|
||||
* fixed nl80211 AP mode configuration regression with Linux 4.15 and
|
||||
newer
|
||||
* added support for using wolfSSL cryptographic library
|
||||
* fixed some 20/40 MHz coexistence cases where the BSS could drop to
|
||||
20 MHz even when 40 MHz would be allowed
|
||||
* Hotspot 2.0
|
||||
- added support for setting Venue URL ANQP-element (venue_url)
|
||||
- added support for advertising Hotspot 2.0 operator icons
|
||||
- added support for Roaming Consortium Selection element
|
||||
- added support for Terms and Conditions
|
||||
- added support for OSEN connection in a shared RSN BSS
|
||||
* added support for using OpenSSL 1.1.1
|
||||
* added EAP-pwd server support for salted passwords
|
||||
|
||||
2016-10-02 - v2.6
|
||||
* fixed EAP-pwd last fragment validation
|
||||
[http://w1.fi/security/2015-7/] (CVE-2015-5314)
|
||||
|
@ -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-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is licensed under the BSD license (the one with
|
||||
@ -70,7 +70,7 @@ Requirements
|
||||
Current hardware/software requirements:
|
||||
- drivers:
|
||||
Host AP driver for Prism2/2.5/3.
|
||||
(http://hostap.epitest.fi/)
|
||||
(http://w1.fi/hostap-driver.html)
|
||||
Please note that station firmware version needs to be 1.7.0 or newer
|
||||
to work in WPA mode.
|
||||
|
||||
@ -81,8 +81,7 @@ Current hardware/software requirements:
|
||||
Any wired Ethernet driver for wired IEEE 802.1X authentication
|
||||
(experimental code)
|
||||
|
||||
FreeBSD -current (with some kernel mods that have not yet been
|
||||
committed when hostapd v0.3.0 was released)
|
||||
FreeBSD -current
|
||||
BSD net80211 layer (e.g., Atheros driver)
|
||||
|
||||
|
||||
@ -186,23 +185,13 @@ Authenticator and RADIUS encapsulation between the Authenticator and
|
||||
the Authentication Server. Other than this, the functionality is similar
|
||||
to the case with the co-located Authentication Server.
|
||||
|
||||
Authentication Server and Supplicant
|
||||
------------------------------------
|
||||
Authentication Server
|
||||
---------------------
|
||||
|
||||
Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
|
||||
Authentication Server with hostapd Authenticator. FreeRADIUS
|
||||
(http://www.freeradius.org/) has been successfully tested with hostapd
|
||||
Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
|
||||
XP Supplicants. EAP/TLS was used with Xsupplicant and
|
||||
EAP/MD5-Challenge with Windows XP.
|
||||
|
||||
http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
|
||||
about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
|
||||
Cisco access point with Host AP driver, hostapd daemon, and a Prism2
|
||||
card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
|
||||
about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
|
||||
configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
|
||||
EAP/TLS use with WinXP Supplicant.
|
||||
Authenticator.
|
||||
|
||||
Automatic WEP key configuration
|
||||
-------------------------------
|
||||
@ -243,16 +232,15 @@ networks that require some kind of security. Task group I (Security)
|
||||
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
|
||||
to address the flaws of the base standard and has in practice
|
||||
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
|
||||
802.11 standard was approved in June 2004 and this amendment is likely
|
||||
to be published in July 2004.
|
||||
802.11 standard was approved in June 2004 and this amendment was
|
||||
published in July 2004.
|
||||
|
||||
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
|
||||
IEEE 802.11i work (draft 3.0) to define a subset of the security
|
||||
enhancements that can be implemented with existing wlan hardware. This
|
||||
is called Wi-Fi Protected Access<TM> (WPA). This has now become a
|
||||
mandatory component of interoperability testing and certification done
|
||||
by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
|
||||
site (http://www.wi-fi.org/OpenSection/protected_access.asp).
|
||||
by Wi-Fi Alliance.
|
||||
|
||||
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
|
||||
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,5 +13,10 @@ struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
int hostapd_set_iface(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss, const char *field,
|
||||
char *value);
|
||||
int hostapd_acl_comp(const void *a, const void *b);
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr);
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr);
|
||||
|
||||
#endif /* CONFIG_FILE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ CONFIG_DRIVER_NL80211=y
|
||||
#CONFIG_LIBNL20=y
|
||||
|
||||
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
|
||||
#CONFIG_LIBNL32=y
|
||||
CONFIG_LIBNL32=y
|
||||
|
||||
|
||||
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
|
||||
@ -50,9 +50,6 @@ CONFIG_IAPP=y
|
||||
# WPA2/IEEE 802.11i RSN pre-authentication
|
||||
CONFIG_RSN_PREAUTH=y
|
||||
|
||||
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
|
||||
CONFIG_PEERKEY=y
|
||||
|
||||
# IEEE 802.11w (management frame protection)
|
||||
CONFIG_IEEE80211W=y
|
||||
|
||||
@ -157,6 +154,12 @@ CONFIG_IPV6=y
|
||||
# IEEE 802.11ac (Very High Throughput) support
|
||||
#CONFIG_IEEE80211AC=y
|
||||
|
||||
# IEEE 802.11ax HE support
|
||||
# Note: This is experimental and work in progress. The definitions are still
|
||||
# subject to change and this should not be expected to interoperate with the
|
||||
# final IEEE 802.11ax version.
|
||||
#CONFIG_IEEE80211AX=y
|
||||
|
||||
# Remove debugging code that is printing out debug messages to stdout.
|
||||
# This can be used to reduce the size of the hostapd considerably if debugging
|
||||
# code is not needed.
|
||||
@ -166,6 +169,9 @@ CONFIG_IPV6=y
|
||||
# Disabled by default.
|
||||
#CONFIG_DEBUG_FILE=y
|
||||
|
||||
# Send debug messages to syslog instead of stdout
|
||||
#CONFIG_DEBUG_SYSLOG=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
|
||||
@ -256,6 +262,7 @@ CONFIG_IPV6=y
|
||||
# openssl = OpenSSL (default)
|
||||
# gnutls = GnuTLS
|
||||
# internal = Internal TLSv1 implementation (experimental)
|
||||
# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
|
||||
# none = Empty template
|
||||
#CONFIG_TLS=openssl
|
||||
|
||||
@ -268,6 +275,10 @@ CONFIG_IPV6=y
|
||||
# can be enabled to enable use of stronger crypto algorithms.
|
||||
#CONFIG_TLSV12=y
|
||||
|
||||
# Select which ciphers to use by default with OpenSSL if the user does not
|
||||
# specify them.
|
||||
#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW"
|
||||
|
||||
# If CONFIG_TLS=internal is used, additional library and include paths are
|
||||
# needed for LibTomMath. Alternatively, an integrated, minimal version of
|
||||
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
|
||||
@ -343,3 +354,22 @@ CONFIG_IPV6=y
|
||||
# a client, from which a signature can be produced which can identify the model
|
||||
# of client device like "Nexus 6P" or "iPhone 5s".
|
||||
#CONFIG_TAXONOMY=y
|
||||
|
||||
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
|
||||
# Note: This is an experimental and not yet complete implementation. This
|
||||
# should not be enabled for production use.
|
||||
#CONFIG_FILS=y
|
||||
# FILS shared key authentication with PFS
|
||||
#CONFIG_FILS_SK_PFS=y
|
||||
|
||||
# Include internal line edit mode in hostapd_cli. This can be used to provide
|
||||
# limited command line editing and history support.
|
||||
#CONFIG_WPA_CLI_EDIT=y
|
||||
|
||||
# Opportunistic Wireless Encryption (OWE)
|
||||
# Experimental implementation of draft-harkins-owe-07.txt
|
||||
#CONFIG_OWE=y
|
||||
|
||||
# Override default value for the wpa_disable_eapol_key_retries configuration
|
||||
# parameter. See that parameter in hostapd.conf for more details.
|
||||
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
|
||||
* Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -973,7 +973,7 @@ static void usage(void)
|
||||
{
|
||||
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
|
||||
"database/authenticator\n"
|
||||
"Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
|
||||
"Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
|
||||
"\n"
|
||||
"usage:\n"
|
||||
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
|
||||
|
@ -98,8 +98,25 @@ ssid=test
|
||||
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
|
||||
# Set as needed to indicate country in which device is operating.
|
||||
# This can limit available channels and transmit power.
|
||||
# These two octets are used as the first two octets of the Country String
|
||||
# (dot11CountryString)
|
||||
#country_code=US
|
||||
|
||||
# The third octet of the Country String (dot11CountryString)
|
||||
# This parameter is used to set the third octet of the country string.
|
||||
#
|
||||
# All environments of the current frequency band and country (default)
|
||||
#country3=0x20
|
||||
# Outdoor environment only
|
||||
#country3=0x4f
|
||||
# Indoor environment only
|
||||
#country3=0x49
|
||||
# Noncountry entity (country_code=XX)
|
||||
#country3=0x58
|
||||
# IEEE 802.11 standard Annex E table indication: 0x01 .. 0x1f
|
||||
# Annex E, Table E-4 (Global operating classes)
|
||||
#country3=0x04
|
||||
|
||||
# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
|
||||
# channels and transmit power levels based on the regulatory limits. The
|
||||
# country_code setting must be configured with the correct country for
|
||||
@ -182,6 +199,11 @@ channel=1
|
||||
#chanlist=100 104 108 112 116
|
||||
#chanlist=1 6 11-13
|
||||
|
||||
# Exclude DFS channels from ACS
|
||||
# This option can be used to exclude all DFS channels from the ACS channel list
|
||||
# in cases where the driver supports DFS channels.
|
||||
#acs_exclude_dfs=1
|
||||
|
||||
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||
beacon_int=100
|
||||
|
||||
@ -227,6 +249,19 @@ fragm_threshold=-1
|
||||
#basic_rates=10 20 55 110
|
||||
#basic_rates=60 120 240
|
||||
|
||||
# Beacon frame TX rate configuration
|
||||
# This sets the TX rate that is used to transmit Beacon frames. If this item is
|
||||
# not included, the driver default rate (likely lowest rate) is used.
|
||||
# Legacy (CCK/OFDM rates):
|
||||
# beacon_rate=<legacy rate in 100 kbps>
|
||||
# HT:
|
||||
# beacon_rate=ht:<HT MCS>
|
||||
# VHT:
|
||||
# beacon_rate=vht:<VHT MCS>
|
||||
#
|
||||
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
|
||||
#beacon_rate=10
|
||||
|
||||
# Short Preamble
|
||||
# This parameter can be used to enable optional use of short preamble for
|
||||
# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
|
||||
@ -294,7 +329,7 @@ ignore_broadcast_ssid=0
|
||||
|
||||
# TX queue parameters (EDCF / bursting)
|
||||
# tx_queue_<queue name>_<param>
|
||||
# queues: data0, data1, data2, data3, after_beacon, beacon
|
||||
# queues: data0, data1, data2, data3
|
||||
# (data0 is the highest priority queue)
|
||||
# parameters:
|
||||
# aifs: AIFS (default 2)
|
||||
@ -476,12 +511,38 @@ wmm_ac_vo_acm=0
|
||||
# Beacon and Probe Response frames.
|
||||
#bss_load_update_period=50
|
||||
|
||||
# Channel utilization averaging period (in BUs)
|
||||
# This field is used to enable and configure channel utilization average
|
||||
# calculation with bss_load_update_period. This should be in multiples of
|
||||
# bss_load_update_period for more accurate calculation.
|
||||
#chan_util_avg_period=600
|
||||
|
||||
# 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
|
||||
|
||||
# Multicast to unicast conversion
|
||||
# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
|
||||
# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
|
||||
# to each station separately, with the DA replaced by their own MAC address
|
||||
# rather than the group address.
|
||||
#
|
||||
# Note that this may break certain expectations of the receiver, such as the
|
||||
# ability to drop unicast IP packets received within multicast L2 frames, or the
|
||||
# ability to not send ICMP destination unreachable messages for packets received
|
||||
# in L2 multicast (which is required, but the receiver can't tell the difference
|
||||
# if this new option is enabled).
|
||||
#
|
||||
# This also doesn't implement the 802.11 DMS (directed multicast service).
|
||||
#
|
||||
#multicast_to_unicast=0
|
||||
|
||||
# Send broadcast Deauthentication frame on AP start/stop
|
||||
# Default: 1 (enabled)
|
||||
#broadcast_deauth=1
|
||||
|
||||
##### IEEE 802.11n related configuration ######################################
|
||||
|
||||
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
|
||||
@ -692,6 +753,47 @@ wmm_ac_vo_acm=0
|
||||
# setting use_sta_nsts=1.
|
||||
#use_sta_nsts=0
|
||||
|
||||
##### IEEE 802.11ax related configuration #####################################
|
||||
|
||||
#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ieee80211ax=1
|
||||
|
||||
#he_su_beamformer: HE single user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#he_su_beamformer=1
|
||||
|
||||
#he_su_beamformee: HE single user beamformee support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#he_su_beamformee=1
|
||||
|
||||
#he_mu_beamformer: HE multiple user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#he_mu_beamformer=1
|
||||
|
||||
# he_bss_color: BSS color
|
||||
# 0 = no BSS color (default)
|
||||
# unsigned integer = BSS color
|
||||
#he_bss_color=0
|
||||
|
||||
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
|
||||
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
|
||||
#he_default_pe_duration=0
|
||||
|
||||
#he_twt_required: Whether TWT is required
|
||||
# 0 = not required (default)
|
||||
# 1 = required
|
||||
#he_twt_required=0
|
||||
|
||||
#he_rts_threshold: Duration of STA transmission
|
||||
# 0 = not set (default)
|
||||
# unsigned integer = duration in units of 16 us
|
||||
#he_rts_threshold=0
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -835,7 +937,8 @@ eap_server=0
|
||||
# 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.
|
||||
# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW"
|
||||
# by default) is used.
|
||||
# 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.
|
||||
@ -1088,6 +1191,8 @@ own_ip_addr=127.0.0.1
|
||||
#radius_das_port=3799
|
||||
#
|
||||
# DAS client (the host that can send Disconnect/CoA requests) and shared secret
|
||||
# Format: <IP address> <shared secret>
|
||||
# IP address 0.0.0.0 can be used to allow requests from any address.
|
||||
#radius_das_client=192.168.1.123 shared secret here
|
||||
#
|
||||
# DAS Event-Timestamp time window in seconds
|
||||
@ -1134,7 +1239,10 @@ own_ip_addr=127.0.0.1
|
||||
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||
# bit0 = WPA
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
|
||||
#wpa=1
|
||||
# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
|
||||
# In other words, for WPA3, wpa=2 is used the configuration (and
|
||||
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
|
||||
#wpa=2
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
@ -1163,31 +1271,73 @@ own_ip_addr=127.0.0.1
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
|
||||
# added to enable SHA256-based stronger algorithms.
|
||||
# WPA-PSK = WPA-Personal / WPA2-Personal
|
||||
# WPA-PSK-SHA256 = WPA2-Personal using SHA256
|
||||
# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
|
||||
# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
|
||||
# SAE = SAE (WPA3-Personal)
|
||||
# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
|
||||
# FT-PSK = FT with passphrase/PSK
|
||||
# FT-EAP = FT with EAP
|
||||
# FT-EAP-SHA384 = FT with EAP using SHA384
|
||||
# FT-SAE = FT with SAE
|
||||
# FILS-SHA256 = Fast Initial Link Setup with SHA256
|
||||
# FILS-SHA384 = Fast Initial Link Setup with SHA384
|
||||
# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
|
||||
# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
|
||||
# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
|
||||
# DPP = Device Provisioning Protocol
|
||||
# OSEN = Hotspot 2.0 online signup with encryption
|
||||
# (dot11RSNAConfigAuthenticationSuitesTable)
|
||||
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||
|
||||
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||
# (unicast packets). This is a space separated list of algorithms:
|
||||
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
|
||||
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
|
||||
# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
|
||||
# TKIP = Temporal Key Integrity Protocol
|
||||
# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
|
||||
# GCMP = Galois/counter mode protocol (GCMP-128)
|
||||
# GCMP-256 = Galois/counter mode protocol with 256-bit key
|
||||
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
|
||||
# is automatically selected based on this configuration. If only CCMP is
|
||||
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||
# TKIP will be used as the group cipher.
|
||||
# TKIP will be used as the group cipher. The optional group_cipher parameter can
|
||||
# be used to override this automatic selection.
|
||||
#
|
||||
# (dot11RSNAConfigPairwiseCiphersTable)
|
||||
# Pairwise cipher for WPA (v1) (default: TKIP)
|
||||
#wpa_pairwise=TKIP CCMP
|
||||
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
|
||||
#rsn_pairwise=CCMP
|
||||
|
||||
# Optional override for automatic group cipher selection
|
||||
# This can be used to select a specific group cipher regardless of which
|
||||
# pairwise ciphers were enabled for WPA and RSN. It should be noted that
|
||||
# overriding the group cipher with an unexpected value can result in
|
||||
# interoperability issues and in general, this parameter is mainly used for
|
||||
# testing purposes.
|
||||
#group_cipher=CCMP
|
||||
|
||||
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||
# seconds. (dot11RSNAConfigGroupRekeyTime)
|
||||
#wpa_group_rekey=600
|
||||
# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
|
||||
# group cipher and 600 seconds (once per 10 minutes) when using TKIP as the
|
||||
# group cipher.
|
||||
#wpa_group_rekey=86400
|
||||
|
||||
# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
|
||||
# (dot11RSNAConfigGroupRekeyStrict)
|
||||
#wpa_strict_rekey=1
|
||||
|
||||
# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is
|
||||
#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount)
|
||||
# This value should only be increased when stations are constantly
|
||||
# deauthenticated during GTK rekeying with the log message
|
||||
# "group key handshake failed...".
|
||||
# You should consider to also increase wpa_pairwise_update_count then.
|
||||
# Range 1..4294967295; default: 4
|
||||
#wpa_group_update_count=4
|
||||
|
||||
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||
# (in seconds).
|
||||
#wpa_gmk_rekey=86400
|
||||
@ -1196,6 +1346,36 @@ own_ip_addr=127.0.0.1
|
||||
# PTK to mitigate some attacks against TKIP deficiencies.
|
||||
#wpa_ptk_rekey=600
|
||||
|
||||
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
|
||||
# Handshake are retried per 4-Way Handshake attempt.
|
||||
# (dot11RSNAConfigPairwiseUpdateCount)
|
||||
# Range 1..4294967295; default: 4
|
||||
#wpa_pairwise_update_count=4
|
||||
|
||||
# Workaround for key reinstallation attacks
|
||||
#
|
||||
# This parameter can be used to disable retransmission of EAPOL-Key frames that
|
||||
# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
|
||||
# is similar to setting wpa_group_update_count=1 and
|
||||
# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
|
||||
# extended timeout on the response to avoid causing issues with stations that
|
||||
# may use aggressive power saving have very long time in replying to the
|
||||
# EAPOL-Key messages.
|
||||
#
|
||||
# This option can be used to work around key reinstallation attacks on the
|
||||
# station (supplicant) side in cases those station devices cannot be updated
|
||||
# for some reason. By removing the retransmissions the attacker cannot cause
|
||||
# key reinstallation with a delayed frame transmission. This is related to the
|
||||
# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
|
||||
# CVE-2017-13080, and CVE-2017-13081.
|
||||
#
|
||||
# This workaround might cause interoperability issues and reduced robustness of
|
||||
# key negotiation especially in environments with heavy traffic load due to the
|
||||
# number of attempts to perform the key exchange is reduced significantly. As
|
||||
# such, this workaround is disabled by default (unless overridden in build
|
||||
# configuration). To enable this, set the parameter to 1.
|
||||
#wpa_disable_eapol_key_retries=1
|
||||
|
||||
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||
# authentication and key handshake before actually associating with a new AP.
|
||||
@ -1211,12 +1391,6 @@ own_ip_addr=127.0.0.1
|
||||
# one.
|
||||
#rsn_preauth_interfaces=eth0
|
||||
|
||||
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
|
||||
# allowed. This is only used with RSN/WPA2.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#peerkey=1
|
||||
|
||||
# ieee80211w: Whether management frame protection (MFP) is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = optional
|
||||
@ -1259,11 +1433,44 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = enabled
|
||||
#okc=1
|
||||
|
||||
# SAE password
|
||||
# This parameter can be used to set passwords for SAE. By default, the
|
||||
# wpa_passphrase value is used if this separate parameter is not used, but
|
||||
# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
|
||||
# SAE passwords do not have such constraints. If the BSS enabled both SAE and
|
||||
# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
|
||||
# uses the wpa_passphrase value.
|
||||
#
|
||||
# Each sae_password entry is added to a list of available passwords. This
|
||||
# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
|
||||
# starts with the password (dot11RSNAConfigPasswordCredential). That value can
|
||||
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
|
||||
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). If the
|
||||
# peer MAC address is not included or is set to the wildcard address
|
||||
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
|
||||
# specific peer MAC address is included, only a station with that MAC address
|
||||
# is allowed to use the entry. If the password identifier (with non-zero length)
|
||||
# is included, the entry is limited to be used only with that specified
|
||||
# identifier. The last matching (based on peer MAC address and identifier) entry
|
||||
# is used to select which password to use. Setting sae_password to an empty
|
||||
# string has a special meaning of removing all previously added entries.
|
||||
# sae_password uses the following encoding:
|
||||
#<password/credential>[|mac=<peer mac>][|id=<identifier>]
|
||||
# Examples:
|
||||
#sae_password=secret
|
||||
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
|
||||
#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
|
||||
|
||||
# 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
|
||||
|
||||
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
|
||||
# The offending SAe peer will be disconnected if more than this many
|
||||
# synchronization errors happen.
|
||||
#sae_sync=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
|
||||
@ -1273,6 +1480,75 @@ own_ip_addr=127.0.0.1
|
||||
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
|
||||
#sae_groups=19 20 21 25 26
|
||||
|
||||
# Require MFP for all associations using SAE
|
||||
# This parameter can be used to enforce negotiation of MFP for all associations
|
||||
# that negotiate use of SAE. This is used in cases where SAE-capable devices are
|
||||
# known to be MFP-capable and the BSS is configured with optional MFP
|
||||
# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
|
||||
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
|
||||
#sae_require_mfp=0
|
||||
|
||||
# FILS Cache Identifier (16-bit value in hexdump format)
|
||||
#fils_cache_id=0011
|
||||
|
||||
# FILS Realm Information
|
||||
# One or more FILS realms need to be configured when FILS is enabled. This list
|
||||
# of realms is used to define which realms (used in keyName-NAI by the client)
|
||||
# can be used with FILS shared key authentication for ERP.
|
||||
#fils_realm=example.com
|
||||
#fils_realm=example.org
|
||||
|
||||
# FILS DH Group for PFS
|
||||
# 0 = PFS disabled with FILS shared key authentication (default)
|
||||
# 1-65535 DH Group to use for FILS PFS
|
||||
#fils_dh_group=0
|
||||
|
||||
# OWE DH groups
|
||||
# OWE implementations are required to support group 19 (NIST P-256). All groups
|
||||
# that are supported by the implementation (e.g., groups 19, 20, and 21 when
|
||||
# using OpenSSL) 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-10
|
||||
#owe_groups=19 20 21
|
||||
|
||||
# OWE transition mode configuration
|
||||
# Pointer to the matching open/OWE BSS
|
||||
#owe_transition_bssid=<bssid>
|
||||
# SSID in same format as ssid2 described above.
|
||||
#owe_transition_ssid=<SSID>
|
||||
# Alternatively, OWE transition mode BSSID/SSID can be configured with a
|
||||
# reference to a BSS operated by this hostapd process.
|
||||
#owe_transition_ifname=<ifname>
|
||||
|
||||
# DHCP server for FILS HLP
|
||||
# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
|
||||
# that include a DHCPDISCOVER message and send them to the specific DHCP
|
||||
# server for processing. hostapd will then wait for a response from that server
|
||||
# before replying with (Re)Association Response frame that encapsulates this
|
||||
# DHCP response. own_ip_addr is used as the local address for the communication
|
||||
# with the DHCP server.
|
||||
#dhcp_server=127.0.0.1
|
||||
|
||||
# DHCP server UDP port
|
||||
# Default: 67
|
||||
#dhcp_server_port=67
|
||||
|
||||
# DHCP relay UDP port on the local device
|
||||
# Default: 67; 0 means not to bind any specific port
|
||||
#dhcp_relay_port=67
|
||||
|
||||
# DHCP rapid commit proxy
|
||||
# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to
|
||||
# allow the rapid commit options (two message DHCP exchange) to be used with a
|
||||
# server that supports only the four message DHCP exchange. This is disabled by
|
||||
# default (= 0) and can be enabled by setting this to 1.
|
||||
#dhcp_rapid_commit_proxy=0
|
||||
|
||||
# Wait time for FILS HLP (dot11HLPWaitTime) in TUs
|
||||
# default: 30 TUs (= 30.72 milliseconds)
|
||||
#fils_hlp_wait_time=30
|
||||
|
||||
##### IEEE 802.11r configuration ##############################################
|
||||
|
||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||
@ -1285,9 +1561,16 @@ own_ip_addr=127.0.0.1
|
||||
# 1 to 48 octet identifier.
|
||||
# This is configured with nas_identifier (see RADIUS client section above).
|
||||
|
||||
# Default lifetime of the PMK-RO in minutes; range 1..65535
|
||||
# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
|
||||
# (default: 14 days / 1209600 seconds; 0 = disable timeout)
|
||||
# (dot11FTR0KeyLifetime)
|
||||
#r0_key_lifetime=10000
|
||||
#ft_r0_key_lifetime=1209600
|
||||
|
||||
# Maximum lifetime for PMK-R1; applied only if not zero
|
||||
# PMK-R1 is removed at latest after this limit.
|
||||
# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
|
||||
# (default: 0)
|
||||
#r1_max_key_lifetime=0
|
||||
|
||||
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
|
||||
# 6-octet identifier as a hex string.
|
||||
@ -1299,22 +1582,52 @@ own_ip_addr=127.0.0.1
|
||||
#reassociation_deadline=1000
|
||||
|
||||
# List of R0KHs in the same Mobility Domain
|
||||
# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
|
||||
# format: <MAC address> <NAS Identifier> <256-bit key as hex string>
|
||||
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
|
||||
# address when requesting PMK-R1 key from the R0KH that the STA used during the
|
||||
# Initial Mobility Domain Association.
|
||||
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
|
||||
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
|
||||
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R0KH.
|
||||
# Wildcard entry:
|
||||
# Upon receiving a response from R0KH, it will be added to this list, so
|
||||
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
|
||||
# blacklisted.
|
||||
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
|
||||
|
||||
# List of R1KHs in the same Mobility Domain
|
||||
# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
|
||||
# format: <MAC address> <R1KH-ID> <256-bit key as hex string>
|
||||
# This list is used to map R1KH-ID to a destination MAC address when sending
|
||||
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
|
||||
# that can request PMK-R1 keys.
|
||||
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
|
||||
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
|
||||
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R1KH.
|
||||
# Wildcard entry:
|
||||
# Upon receiving a request from an R1KH not yet known, it will be added to this
|
||||
# list and thus will receive push notifications.
|
||||
#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
|
||||
|
||||
# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
|
||||
# Special values: 0 -> do not expire
|
||||
# Warning: do not cache implies no sequence number validation with wildcards
|
||||
#rkh_pos_timeout=86400 (default = 1 day)
|
||||
|
||||
# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request
|
||||
# and number of retries.
|
||||
#rkh_pull_timeout=1000 (default = 1 second)
|
||||
#rkh_pull_retries=4 (default)
|
||||
|
||||
# Timeout (seconds) for non replying R0KH (see wildcard entries above)
|
||||
# Special values: 0 -> do not cache
|
||||
# default: 60 seconds
|
||||
#rkh_neg_timeout=60
|
||||
|
||||
# Note: The R0KH/R1KH keys used to be 128-bit in length before the message
|
||||
# format was changed. That shorter key length is still supported for backwards
|
||||
# compatibility of the configuration files. If such a shorter key is used, a
|
||||
# 256-bit key is derived from it. For new deployments, configuring the 256-bit
|
||||
# key is recommended.
|
||||
|
||||
# Whether PMK-R1 push is enabled at R0KH
|
||||
# 0 = do not push PMK-R1 to all configured R1KHs (default)
|
||||
@ -1326,6 +1639,14 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = FT-over-DS enabled (default)
|
||||
#ft_over_ds=1
|
||||
|
||||
# Whether to generate FT response locally for PSK networks
|
||||
# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as
|
||||
# the required information (PSK and other session data) is already locally
|
||||
# available.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ft_psk_generate_local=0
|
||||
|
||||
##### Neighbor table ##########################################################
|
||||
# Maximum number of entries kept in AP table (either for neigbor table or for
|
||||
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||
@ -1596,6 +1917,18 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = enabled (allow stations to use WNM-Sleep Mode)
|
||||
#wnm_sleep_mode=1
|
||||
|
||||
# WNM-Sleep Mode GTK/IGTK workaround
|
||||
# Normally, WNM-Sleep Mode exit with management frame protection negotiated
|
||||
# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
|
||||
# Response frame. Some station implementations may have a vulnerability that
|
||||
# results in GTK/IGTK reinstallation based on this frame being replayed. This
|
||||
# configuration parameter can be used to disable that behavior and use EAPOL-Key
|
||||
# frames for GTK/IGTK update instead. This would likely be only used with
|
||||
# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
|
||||
# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
|
||||
# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
|
||||
#wnm_sleep_mode_no_keys=0
|
||||
|
||||
# BSS Transition Management
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
@ -1683,6 +2016,15 @@ own_ip_addr=127.0.0.1
|
||||
# (double quoted string, printf-escaped string)
|
||||
#venue_name=P"eng:Example\nvenue"
|
||||
|
||||
# Venue URL information
|
||||
# This parameter can be used to configure one or more Venue URL Duples to
|
||||
# provide additional information corresponding to Venue Name information.
|
||||
# Each entry has a Venue Number value separated by colon from the Venue URL
|
||||
# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
|
||||
# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
|
||||
#venue_url=1:http://www.example.com/info-eng
|
||||
#venue_url=2:http://www.example.com/info-fin
|
||||
|
||||
# Network Authentication Type
|
||||
# This parameter indicates what type of network authentication is used in the
|
||||
# network.
|
||||
@ -1853,7 +2195,27 @@ own_ip_addr=127.0.0.1
|
||||
# channels 36-48):
|
||||
#hs20_operating_class=5173
|
||||
|
||||
# OSU icons
|
||||
# Terms and Conditions information
|
||||
#
|
||||
# hs20_t_c_filename contains the Terms and Conditions filename that the AP
|
||||
# indicates in RADIUS Access-Request messages.
|
||||
#hs20_t_c_filename=terms-and-conditions
|
||||
#
|
||||
# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
|
||||
# indicates in RADIUS Access-Request messages. Usually, this contains the number
|
||||
# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
|
||||
# last modified.
|
||||
#hs20_t_c_timestamp=1234567
|
||||
#
|
||||
# hs20_t_c_server_url contains a template for the Terms and Conditions server
|
||||
# URL. This template is used to generate the URL for a STA that needs to
|
||||
# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
|
||||
# parameter is used on the authentication server, not the AP.
|
||||
# Macros:
|
||||
# @1@ = MAC address of the STA (colon separated hex octets)
|
||||
#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
|
||||
|
||||
# OSU and Operator 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
|
||||
@ -1865,12 +2227,15 @@ own_ip_addr=127.0.0.1
|
||||
# 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.
|
||||
# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
|
||||
# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
|
||||
# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
|
||||
#
|
||||
#osu_server_uri=https://example.com/osu/
|
||||
#osu_friendly_name=eng:Example operator
|
||||
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
|
||||
#osu_nai=anonymous@example.com
|
||||
#osu_nai2=anonymous@example.com
|
||||
#osu_method_list=1 0
|
||||
#osu_icon=icon32
|
||||
#osu_icon=icon64
|
||||
@ -1879,6 +2244,35 @@ own_ip_addr=127.0.0.1
|
||||
#
|
||||
#osu_server_uri=...
|
||||
|
||||
# Operator Icons
|
||||
# Operator icons are specified using references to the hs20_icon entries
|
||||
# (Name subfield). This information, if present, is advertsised in the
|
||||
# Operator Icon Metadata ANQO-element.
|
||||
#operator_icon=icon32
|
||||
#operator_icon=icon64
|
||||
|
||||
##### Multiband Operation (MBO) ###############################################
|
||||
#
|
||||
# MBO enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#mbo=1
|
||||
#
|
||||
# Cellular data connection preference
|
||||
# 0 = Excluded - AP does not want STA to use the cellular data connection
|
||||
# 1 = AP prefers the STA not to use cellular data connection
|
||||
# 255 = AP prefers the STA to use cellular data connection
|
||||
#mbo_cell_data_conn_pref=1
|
||||
|
||||
##### Optimized Connectivity Experience (OCE) #################################
|
||||
#
|
||||
# Enable OCE specific features (bitmap)
|
||||
# BIT(0) - Reserved
|
||||
# Set BIT(1) (= 2) to enable OCE in STA-CFON mode
|
||||
# Set BIT(2) (= 4) to enable OCE in AP mode
|
||||
# Default is 0 = OCE disabled
|
||||
#oce=0
|
||||
|
||||
##### Fast Session Transfer (FST) support #####################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
@ -1916,6 +2310,9 @@ own_ip_addr=127.0.0.1
|
||||
# Enable neighbor report via radio measurements
|
||||
#rrm_neighbor_report=1
|
||||
|
||||
# Enable beacon report via radio measurements
|
||||
#rrm_beacon_report=1
|
||||
|
||||
# Publish fine timing measurement (FTM) responder functionality
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
@ -1925,6 +2322,12 @@ own_ip_addr=127.0.0.1
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
#ftm_initiator=0
|
||||
#
|
||||
# Stationary AP config indicates that the AP doesn't move hence location data
|
||||
# can be considered as always up to date. If configured, LCI data will be sent
|
||||
# as a radio measurement even if the request doesn't contain a max age element
|
||||
# that allows sending of such data. Default: 0.
|
||||
#stationary_ap=0
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
|
@ -3,7 +3,8 @@ CREATE TABLE users(
|
||||
methods TEXT,
|
||||
password TEXT,
|
||||
remediation TEXT,
|
||||
phase2 INTEGER
|
||||
phase2 INTEGER,
|
||||
t_c_timestamp INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE wildcards(
|
||||
@ -24,3 +25,18 @@ CREATE TABLE authlog(
|
||||
username TEXT,
|
||||
note TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE pending_tc(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE current_sessions(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT,
|
||||
start_time TEXT,
|
||||
nas TEXT,
|
||||
hs20_t_c_filtering BOOLEAN,
|
||||
waiting_coa_ack BOOLEAN,
|
||||
coa_ack_received BOOLEAN
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - command line interface for hostapd daemon
|
||||
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
|
||||
"Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
@ -45,6 +45,8 @@ static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
|
||||
static void print_help(FILE *stream, const char *cmd);
|
||||
static char ** list_cmd_list(void);
|
||||
static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
|
||||
static void update_stations(struct wpa_ctrl *ctrl);
|
||||
static void cli_event(const char *str);
|
||||
|
||||
|
||||
static void usage(void)
|
||||
@ -147,13 +149,45 @@ static void hostapd_cli_close_connection(void)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_reconnect(const char *ifname)
|
||||
{
|
||||
char *next_ctrl_ifname;
|
||||
|
||||
hostapd_cli_close_connection();
|
||||
|
||||
if (!ifname)
|
||||
return -1;
|
||||
|
||||
next_ctrl_ifname = os_strdup(ifname);
|
||||
os_free(ctrl_ifname);
|
||||
ctrl_ifname = next_ctrl_ifname;
|
||||
if (!ctrl_ifname)
|
||||
return -1;
|
||||
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (!ctrl_conn)
|
||||
return -1;
|
||||
if (!interactive && !action_file)
|
||||
return 0;
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
update_stations(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_msg_cb(char *msg, size_t len)
|
||||
{
|
||||
cli_event(msg);
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
|
||||
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len;
|
||||
@ -181,7 +215,7 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
}
|
||||
|
||||
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
|
||||
{
|
||||
return _wpa_ctrl_command(ctrl, cmd, 1);
|
||||
}
|
||||
@ -286,6 +320,21 @@ static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_stations(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -318,21 +367,6 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_deauthenticate(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -351,21 +385,6 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_disassociate(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
@ -701,8 +720,8 @@ static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
char *addr, size_t addr_len)
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
|
||||
char *addr, size_t addr_len, int print)
|
||||
{
|
||||
char buf[4096], *pos;
|
||||
size_t len;
|
||||
@ -726,7 +745,8 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
buf[len] = '\0';
|
||||
if (memcmp(buf, "FAIL", 4) == 0)
|
||||
return -1;
|
||||
printf("%s", buf);
|
||||
if (print)
|
||||
printf("%s", buf);
|
||||
|
||||
pos = buf;
|
||||
while (*pos != '\0' && *pos != '\n')
|
||||
@ -742,16 +762,33 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
do {
|
||||
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
|
||||
return 0;
|
||||
do {
|
||||
if (os_strcmp(addr, "") != 0)
|
||||
printf("%s\n", addr);
|
||||
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
print_help(stdout, argc > 0 ? argv[0] : NULL);
|
||||
@ -888,6 +925,25 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static void update_stations(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (!ctrl || !interactive)
|
||||
return;
|
||||
|
||||
cli_txt_list_flush(&stations);
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
|
||||
return;
|
||||
do {
|
||||
if (os_strcmp(addr, "") != 0)
|
||||
cli_txt_list_add(&stations, addr);
|
||||
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
|
||||
struct dl_list *interfaces)
|
||||
{
|
||||
@ -940,23 +996,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
hostapd_cli_list_interfaces(ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hostapd_cli_close_connection();
|
||||
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);
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
} else {
|
||||
if (hostapd_cli_reconnect(argv[0]) != 0) {
|
||||
printf("Could not connect to interface '%s' - re-trying\n",
|
||||
ctrl_ifname);
|
||||
}
|
||||
@ -984,7 +1024,7 @@ static char ** hostapd_complete_interface(const char *str, int pos)
|
||||
|
||||
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
char cmd[2048];
|
||||
int res;
|
||||
|
||||
if (argc != 2) {
|
||||
@ -1002,6 +1042,44 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_set(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
const char *fields[] = {
|
||||
#ifdef CONFIG_WPS_TESTING
|
||||
"wps_version_number", "wps_testing_dummy_cred",
|
||||
"wps_corrupt_pkhash",
|
||||
#endif /* CONFIG_WPS_TESTING */
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
"gas_frag_limit",
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
"ext_mgmt_frame_handling", "ext_eapol_frame_io",
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_MBO
|
||||
"mbo_assoc_disallow",
|
||||
#endif /* CONFIG_MBO */
|
||||
"deny_mac_file", "accept_mac_file",
|
||||
};
|
||||
int i, num_fields = ARRAY_SIZE(fields);
|
||||
|
||||
if (arg == 1) {
|
||||
char **res;
|
||||
|
||||
res = os_calloc(num_fields + 1, sizeof(char *));
|
||||
if (!res)
|
||||
return NULL;
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
res[i] = os_strdup(fields[i]);
|
||||
if (!res[i])
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
@ -1022,6 +1100,31 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_get(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
const char *fields[] = {
|
||||
"version", "tls_library",
|
||||
};
|
||||
int i, num_fields = ARRAY_SIZE(fields);
|
||||
|
||||
if (arg == 1) {
|
||||
char **res;
|
||||
|
||||
res = os_calloc(num_fields + 1, sizeof(char *));
|
||||
if (!res)
|
||||
return NULL;
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
res[i] = os_strdup(fields[i]);
|
||||
if (!res[i])
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
@ -1185,14 +1288,14 @@ static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
|
||||
char cmd[2048];
|
||||
int res;
|
||||
|
||||
if (argc < 3 || argc > 5) {
|
||||
printf("Invalid set_neighbor command: needs 3-5 arguments\n");
|
||||
if (argc < 3 || argc > 6) {
|
||||
printf("Invalid set_neighbor command: needs 3-6 arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
|
||||
res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
|
||||
argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
|
||||
argc == 5 ? argv[4] : "");
|
||||
argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long SET_NEIGHBOR command.\n");
|
||||
return -1;
|
||||
@ -1261,6 +1364,122 @@ static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
@ -1273,26 +1492,30 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"= pings hostapd" },
|
||||
{ "mib", hostapd_cli_cmd_mib, NULL,
|
||||
"= get MIB variables (dot1x, dot11, radius)" },
|
||||
{ "relog", hostapd_cli_cmd_relog, NULL, NULL },
|
||||
{ "status", hostapd_cli_cmd_status, NULL, NULL },
|
||||
{ "sta", hostapd_cli_cmd_sta, NULL,
|
||||
{ "relog", hostapd_cli_cmd_relog, NULL,
|
||||
"= reload/truncate debug log output file" },
|
||||
{ "status", hostapd_cli_cmd_status, NULL,
|
||||
"= show interface status info" },
|
||||
{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
|
||||
"<addr> = get MIB variables for one station" },
|
||||
{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
|
||||
"= get MIB variables for all stations" },
|
||||
{ "list_sta", hostapd_cli_cmd_list_sta, NULL,
|
||||
"= list all stations" },
|
||||
{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
|
||||
"<addr> = add a new station" },
|
||||
{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
|
||||
hostapd_complete_deauthenticate,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = deauthenticate a station" },
|
||||
{ "disassociate", hostapd_cli_cmd_disassociate,
|
||||
hostapd_complete_disassociate,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = disassociate a station" },
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
{ "signature", hostapd_cli_cmd_signature, NULL,
|
||||
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
|
||||
"<addr> = get taxonomy signature for a station" },
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
|
||||
"<addr> = send SA Query to a station" },
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WPS
|
||||
@ -1321,9 +1544,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
|
||||
"= show current WPS status" },
|
||||
#endif /* CONFIG_WPS */
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
|
||||
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
|
||||
"= send Disassociation Imminent notification" },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
|
||||
"= send ESS Dissassociation Imminent notification" },
|
||||
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
|
||||
"= send BSS Transition Management Request" },
|
||||
{ "get_config", hostapd_cli_cmd_get_config, NULL,
|
||||
"= show current configuration" },
|
||||
{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
|
||||
@ -1331,35 +1557,100 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
|
||||
"[ifname] = show interfaces/select interface" },
|
||||
#ifdef CONFIG_FST
|
||||
{ "fst", hostapd_cli_cmd_fst, NULL, NULL },
|
||||
{ "fst", hostapd_cli_cmd_fst, NULL,
|
||||
"<params...> = send FST-MANAGER control interface command" },
|
||||
#endif /* CONFIG_FST */
|
||||
{ "raw", hostapd_cli_cmd_raw, NULL, NULL },
|
||||
{ "raw", hostapd_cli_cmd_raw, NULL,
|
||||
"<params..> = send unprocessed command" },
|
||||
{ "level", hostapd_cli_cmd_level, NULL,
|
||||
"<debug level> = change debug level" },
|
||||
{ "license", hostapd_cli_cmd_license, NULL,
|
||||
"= show full hostapd_cli license" },
|
||||
{ "quit", hostapd_cli_cmd_quit, NULL,
|
||||
"= exit hostapd_cli" },
|
||||
{ "set", hostapd_cli_cmd_set, NULL, NULL },
|
||||
{ "get", hostapd_cli_cmd_get, NULL, NULL },
|
||||
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
|
||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
|
||||
{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
|
||||
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
|
||||
{ "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
|
||||
{ "enable", hostapd_cli_cmd_enable, NULL, NULL },
|
||||
{ "reload", hostapd_cli_cmd_reload, NULL, NULL },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL, NULL },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
|
||||
{ "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
|
||||
{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
|
||||
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
|
||||
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
|
||||
{ "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
|
||||
{ "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
|
||||
{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
|
||||
{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
|
||||
"<name> <value> = set runtime variables" },
|
||||
{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
|
||||
"<name> = get runtime info" },
|
||||
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
|
||||
"<arg,arg,...> = set QoS Map set element" },
|
||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = send QoS Map Configure frame" },
|
||||
{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
|
||||
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
|
||||
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
|
||||
" = initiate channel switch announcement" },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
|
||||
"<addr> <url>\n"
|
||||
" = send WNM-Notification Subscription Remediation Request" },
|
||||
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
|
||||
"<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
|
||||
" = send WNM-Notification imminent deauthentication indication" },
|
||||
{ "vendor", hostapd_cli_cmd_vendor, NULL,
|
||||
"<vendor id> <sub command id> [<hex formatted data>]\n"
|
||||
" = send vendor driver command" },
|
||||
{ "enable", hostapd_cli_cmd_enable, NULL,
|
||||
"= enable hostapd on current interface" },
|
||||
{ "reload", hostapd_cli_cmd_reload, NULL,
|
||||
"= reload configuration for current interface" },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL,
|
||||
"= disable hostapd on current interface" },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
|
||||
"= drop all ERP keys"},
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL,
|
||||
"[level] = show/change log verbosity level" },
|
||||
{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
|
||||
" = show PMKSA cache entries" },
|
||||
{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
|
||||
" = flush PMKSA cache" },
|
||||
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
|
||||
"<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
|
||||
" = add AP to neighbor database" },
|
||||
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
|
||||
"<addr> <ssid=> = remove AP from neighbor database" },
|
||||
{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
|
||||
"<addr> = send LCI request to a station"},
|
||||
{ "req_range", hostapd_cli_cmd_req_range, NULL,
|
||||
" = send FTM range request"},
|
||||
{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
|
||||
" = show supported driver flags"},
|
||||
#ifdef CONFIG_DPP
|
||||
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
|
||||
"report a scanned DPP URI from a QR Code" },
|
||||
{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
|
||||
"type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
|
||||
{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
|
||||
"*|<id> = remove DPP bootstrap information" },
|
||||
{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
|
||||
"<id> = get DPP bootstrap URI" },
|
||||
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
|
||||
"<id> = show DPP bootstrap information" },
|
||||
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
|
||||
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
|
||||
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
|
||||
"<freq in MHz> = start DPP listen" },
|
||||
{ "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
|
||||
"= stop DPP listen" },
|
||||
{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
|
||||
"[curve=..] [key=..] = add DPP configurator" },
|
||||
{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
|
||||
NULL,
|
||||
"*|<id> = remove DPP configurator" },
|
||||
{ "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
|
||||
NULL,
|
||||
"<id> = Get DPP configurator's private key" },
|
||||
{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
|
||||
"add PKEX code" },
|
||||
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
|
||||
"*|<id> = remove DPP pkex information" },
|
||||
#endif /* CONFIG_DPP */
|
||||
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear accept MAC ACL" },
|
||||
{ "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear deny MAC ACL" },
|
||||
{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
|
||||
"<addr> = poll a STA to check connectivity with a QoS null frame" },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -1471,7 +1762,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
while (wpa_ctrl_pending(ctrl)) {
|
||||
char buf[256];
|
||||
char buf[4096];
|
||||
size_t len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||
buf[len] = '\0';
|
||||
@ -1504,19 +1795,8 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
|
||||
printf("Connection to hostapd lost - trying to reconnect\n");
|
||||
hostapd_cli_close_connection();
|
||||
}
|
||||
if (!ctrl_conn) {
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (ctrl_conn)
|
||||
hostapd_cli_recv_pending(ctrl_conn, 1, 0);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
@ -1611,17 +1891,34 @@ static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
|
||||
|
||||
static void hostapd_cli_interactive(void)
|
||||
{
|
||||
char *hfile = NULL;
|
||||
char *home;
|
||||
|
||||
printf("\nInteractive mode\n\n");
|
||||
|
||||
#ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
|
||||
home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
|
||||
#else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
|
||||
home = getenv("HOME");
|
||||
#endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
|
||||
if (home) {
|
||||
const char *fname = ".hostapd_cli_history";
|
||||
int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
|
||||
hfile = os_malloc(hfile_len);
|
||||
if (hfile)
|
||||
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
|
||||
}
|
||||
|
||||
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
|
||||
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
|
||||
hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
|
||||
hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
|
||||
eloop_run();
|
||||
|
||||
cli_txt_list_flush(&stations);
|
||||
edit_deinit(NULL, NULL);
|
||||
edit_deinit(hfile, NULL);
|
||||
os_free(hfile);
|
||||
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
|
||||
}
|
||||
|
||||
@ -1748,7 +2045,7 @@ int main(int argc, char *argv[])
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
hostapd_cli_reconnect(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
if (warning_displayed)
|
||||
printf("Connection established.\n");
|
||||
@ -1769,17 +2066,8 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interactive || action_file) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
if (action_file)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action_file && !hostapd_cli_attached)
|
||||
return -1;
|
||||
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
|
||||
return -1;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / main()
|
||||
* Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -24,6 +24,7 @@
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/ap_drv_ops.h"
|
||||
#include "ap/dpp_hostapd.h"
|
||||
#include "fst/fst.h"
|
||||
#include "config_file.h"
|
||||
#include "eap_register.h"
|
||||
@ -108,6 +109,10 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
|
||||
module_str ? module_str : "",
|
||||
module_str ? ": " : "", txt);
|
||||
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
if (wpa_debug_syslog)
|
||||
conf_stdout = 0;
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
if ((conf_stdout & module) && level >= conf_stdout_level) {
|
||||
wpa_debug_print_timestamp();
|
||||
wpa_printf(MSG_INFO, "%s", format);
|
||||
@ -248,7 +253,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
*
|
||||
* 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.
|
||||
* interfaces. No actual driver operations are started.
|
||||
*/
|
||||
static struct hostapd_iface *
|
||||
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
|
||||
@ -451,7 +456,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-2016, Jouni Malinen <j@w1.fi> "
|
||||
"Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
|
||||
@ -480,10 +485,13 @@ static void usage(void)
|
||||
" -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"
|
||||
" -T record to Linux tracing in addition to logging\n"
|
||||
" (records all messages regardless of debug verbosity)\n"
|
||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||
" -i list of interface names to use\n"
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
" -s log output to syslog instead of stdout\n"
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
" -S start all the interfaces synchronously\n"
|
||||
" -t include timestamps in some debug messages\n"
|
||||
" -v show hostapd version\n");
|
||||
@ -549,14 +557,14 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
|
||||
|
||||
static int hostapd_get_interface_names(char ***if_names,
|
||||
size_t *if_names_size,
|
||||
char *optarg)
|
||||
char *arg)
|
||||
{
|
||||
char *if_name, *tmp, **nnames;
|
||||
size_t i;
|
||||
|
||||
if (!optarg)
|
||||
if (!arg)
|
||||
return -1;
|
||||
if_name = strtok_r(optarg, ",", &tmp);
|
||||
if_name = strtok_r(arg, ",", &tmp);
|
||||
|
||||
while (if_name) {
|
||||
nnames = os_realloc_array(*if_names, 1 + *if_names_size,
|
||||
@ -659,9 +667,15 @@ int main(int argc, char *argv[])
|
||||
interfaces.global_iface_name = NULL;
|
||||
interfaces.global_ctrl_sock = -1;
|
||||
dl_list_init(&interfaces.global_ctrl_dst);
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
dl_list_init(&interfaces.eth_p_oui);
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_init_global(&interfaces);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -718,6 +732,11 @@ int main(int argc, char *argv[])
|
||||
bss_config = tmp_bss;
|
||||
bss_config[num_bss_configs++] = optarg;
|
||||
break;
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
case 's':
|
||||
wpa_debug_syslog = 1;
|
||||
break;
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
case 'S':
|
||||
start_ifaces_in_sync = 1;
|
||||
break;
|
||||
@ -746,6 +765,10 @@ int main(int argc, char *argv[])
|
||||
wpa_debug_open_file(log_file);
|
||||
else
|
||||
wpa_debug_setup_stdout();
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
if (wpa_debug_syslog)
|
||||
wpa_debug_open_syslog();
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||
if (enable_trace_dbg) {
|
||||
int tret = wpa_debug_open_linux_tracing();
|
||||
@ -877,11 +900,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit_global(&interfaces);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (interfaces.eloop_initialized)
|
||||
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
|
||||
hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
|
||||
os_free(pid_file);
|
||||
|
||||
wpa_debug_close_syslog();
|
||||
if (log_file)
|
||||
wpa_debug_close_file();
|
||||
wpa_debug_close_linux_tracing();
|
||||
|
@ -666,7 +666,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
|
||||
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;
|
||||
@ -721,11 +720,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
|
||||
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) {
|
||||
|
@ -111,6 +111,12 @@ static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
|
||||
xml_node_t *syncml, *synchdr;
|
||||
xml_namespace_t *ns;
|
||||
|
||||
if (!ctx->devid) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"DevId from devinfo.xml is not available - cannot use OMA DM");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
|
||||
"SyncML");
|
||||
|
||||
|
@ -105,6 +105,35 @@ static int valid_fqdn(const char *fqdn)
|
||||
}
|
||||
|
||||
|
||||
static int android_update_permission(const char *path, mode_t mode)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
/* we need to change file/folder permission for Android */
|
||||
|
||||
if (!path) {
|
||||
wpa_printf(MSG_ERROR, "file path null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allow processes running with Group ID as AID_WIFI,
|
||||
* to read files from SP, SP/<fqdn>, Cert and osu-info directories */
|
||||
if (chown(path, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chmod(path, mode) < 0) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
|
||||
{
|
||||
xml_node_t *node;
|
||||
@ -169,6 +198,8 @@ int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
|
||||
}
|
||||
|
||||
mkdir("Cert", S_IRWXU);
|
||||
android_update_permission("Cert", S_IRWXU | S_IRWXG);
|
||||
|
||||
if (est_load_cacerts(ctx, url) < 0 ||
|
||||
est_build_csr(ctx, url) < 0 ||
|
||||
est_simple_enroll(ctx, url, user, pw) < 0)
|
||||
@ -262,7 +293,6 @@ static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
|
||||
|
||||
unlink("Cert/est-req.b64");
|
||||
unlink("Cert/est-req.pem");
|
||||
unlink("Cert/est-resp.raw");
|
||||
rmdir("Cert");
|
||||
|
||||
return 0;
|
||||
@ -406,7 +436,7 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
|
||||
if (node == NULL) {
|
||||
wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
|
||||
xml_node_free(ctx->xml, pps);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = download_cert(ctx, node, ca_fname);
|
||||
@ -433,7 +463,7 @@ static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
|
||||
if (node == NULL) {
|
||||
wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
|
||||
xml_node_free(ctx->xml, pps);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
aaa = xml_node_first_child(ctx->xml, node);
|
||||
@ -455,7 +485,7 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
|
||||
{
|
||||
char *dir, *pos;
|
||||
char fname[300];
|
||||
int ret;
|
||||
int ret, ret1;
|
||||
|
||||
dir = os_strdup(pps_fname);
|
||||
if (dir == NULL)
|
||||
@ -470,9 +500,13 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
|
||||
snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
|
||||
ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
|
||||
snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
|
||||
cmd_dl_polupd_ca(ctx, pps_fname, fname);
|
||||
ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
|
||||
if (ret == 0 && ret1 == -1)
|
||||
ret = -1;
|
||||
snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
|
||||
cmd_dl_aaa_ca(ctx, pps_fname, fname);
|
||||
ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
|
||||
if (ret == 0 && ret1 == -1)
|
||||
ret = -1;
|
||||
|
||||
os_free(dir);
|
||||
|
||||
@ -578,20 +612,8 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Allow processes running with Group ID as AID_WIFI,
|
||||
* to read files from SP/<fqdn> directory */
|
||||
if (chown(fname, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
|
||||
strerror(errno));
|
||||
/* Try to continue anyway */
|
||||
}
|
||||
if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
|
||||
strerror(errno));
|
||||
/* Try to continue anyway */
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
android_update_permission("SP", S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
android_update_permission(fname, S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
|
||||
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
|
||||
|
||||
@ -1213,8 +1235,7 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
|
||||
homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
|
||||
} else {
|
||||
if (set_cred_quoted(ctx->ifname, id, "roaming_consortium",
|
||||
homeoi) < 0)
|
||||
if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
|
||||
}
|
||||
|
||||
@ -1289,7 +1310,9 @@ static void set_pps_cred_home_sp_roaming_consortium_oi(
|
||||
if (str == NULL)
|
||||
return;
|
||||
wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
|
||||
/* TODO: Set to wpa_supplicant */
|
||||
if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums",
|
||||
str) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums");
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
}
|
||||
|
||||
@ -1442,10 +1465,92 @@ static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id,
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx,
|
||||
int id, xml_node_t *node)
|
||||
{
|
||||
char *str = xml_node_get_text(ctx->xml, node);
|
||||
int type;
|
||||
const char *eap_method = NULL;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
wpa_printf(MSG_INFO,
|
||||
"- Credential/UsernamePassword/EAPMethod/EAPType = %s", str);
|
||||
type = atoi(str);
|
||||
switch (type) {
|
||||
case EAP_TYPE_TLS:
|
||||
eap_method = "TLS";
|
||||
break;
|
||||
case EAP_TYPE_TTLS:
|
||||
eap_method = "TTLS";
|
||||
break;
|
||||
case EAP_TYPE_PEAP:
|
||||
eap_method = "PEAP";
|
||||
break;
|
||||
case EAP_TYPE_PWD:
|
||||
eap_method = "PWD";
|
||||
break;
|
||||
}
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
if (!eap_method) {
|
||||
wpa_printf(MSG_INFO, "Unknown EAPType value");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_cred(ctx->ifname, id, "eap", eap_method) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred eap");
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx,
|
||||
int id, xml_node_t *node)
|
||||
{
|
||||
char *str = xml_node_get_text(ctx->xml, node);
|
||||
const char *phase2 = NULL;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
wpa_printf(MSG_INFO,
|
||||
"- Credential/UsernamePassword/EAPMethod/InnerMethod = %s",
|
||||
str);
|
||||
if (os_strcmp(str, "PAP") == 0)
|
||||
phase2 = "auth=PAP";
|
||||
else if (os_strcmp(str, "CHAP") == 0)
|
||||
phase2 = "auth=CHAP";
|
||||
else if (os_strcmp(str, "MS-CHAP") == 0)
|
||||
phase2 = "auth=MSCHAP";
|
||||
else if (os_strcmp(str, "MS-CHAP-V2") == 0)
|
||||
phase2 = "auth=MSCHAPV2";
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
if (!phase2) {
|
||||
wpa_printf(MSG_INFO, "Unknown InnerMethod value");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred phase2");
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id,
|
||||
xml_node_t *node)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod - TODO");
|
||||
xml_node_t *child;
|
||||
const char *name;
|
||||
|
||||
wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod");
|
||||
|
||||
xml_node_for_each_child(ctx->xml, child, node) {
|
||||
xml_node_for_each_check(ctx->xml, child);
|
||||
name = xml_node_get_localname(ctx->xml, child);
|
||||
if (os_strcasecmp(name, "EAPType") == 0)
|
||||
set_pps_cred_eap_method_eap_type(ctx, id, child);
|
||||
else if (os_strcasecmp(name, "InnerMethod") == 0)
|
||||
set_pps_cred_eap_method_inner_method(ctx, id, child);
|
||||
else
|
||||
wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1884,7 +1989,9 @@ struct osu_data {
|
||||
char url[256];
|
||||
unsigned int methods;
|
||||
char osu_ssid[33];
|
||||
char osu_ssid2[33];
|
||||
char osu_nai[256];
|
||||
char osu_nai2[256];
|
||||
struct osu_lang_text friendly_name[MAX_OSU_VALS];
|
||||
size_t friendly_name_count;
|
||||
struct osu_lang_text serv_desc[MAX_OSU_VALS];
|
||||
@ -1943,12 +2050,24 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "osu_ssid2=", 10) == 0) {
|
||||
snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
|
||||
"%s", buf + 10);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
|
||||
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
|
||||
"%s", buf + 8);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
|
||||
os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
|
||||
"%s", buf + 9);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "friendly_name=", 14) == 0) {
|
||||
struct osu_lang_text *txt;
|
||||
if (last->friendly_name_count == MAX_OSU_VALS)
|
||||
@ -2024,9 +2143,9 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
|
||||
|
||||
static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
const char *ssid, const char *url,
|
||||
const char *ssid, const char *ssid2, const char *url,
|
||||
unsigned int methods, int no_prod_assoc,
|
||||
const char *osu_nai)
|
||||
const char *osu_nai, const char *osu_nai2)
|
||||
{
|
||||
int id;
|
||||
const char *ifname = ctx->ifname;
|
||||
@ -2034,26 +2153,54 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
struct wpa_ctrl *mon;
|
||||
int res;
|
||||
|
||||
if (ssid2 && ssid2[0] == '\0')
|
||||
ssid2 = NULL;
|
||||
|
||||
if (ctx->osu_ssid) {
|
||||
if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Enforced OSU SSID matches ANQP info");
|
||||
ssid2 = NULL;
|
||||
} else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Enforced OSU SSID matches RSN[OSEN] info");
|
||||
ssid = ssid2;
|
||||
} else {
|
||||
wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
|
||||
write_summary(ctx, "Enforced OSU SSID did not match");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
id = add_network(ifname);
|
||||
if (id < 0)
|
||||
return -1;
|
||||
if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
|
||||
return -1;
|
||||
if (ssid2)
|
||||
osu_nai = osu_nai2;
|
||||
if (osu_nai && os_strlen(osu_nai) > 0) {
|
||||
char dir[255], fname[300];
|
||||
if (getcwd(dir, sizeof(dir)) == NULL)
|
||||
return -1;
|
||||
os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
|
||||
|
||||
if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
|
||||
return -1;
|
||||
|
||||
if (set_network(ifname, id, "proto", "OSEN") < 0 ||
|
||||
set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
|
||||
set_network(ifname, id, "pairwise", "CCMP") < 0 ||
|
||||
set_network(ifname, id, "group", "GTK_NOT_USED") < 0 ||
|
||||
set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
|
||||
set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
|
||||
set_network(ifname, id, "ocsp", "2") < 0 ||
|
||||
set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
|
||||
set_network_quoted(ifname, id, "ca_cert", fname) < 0)
|
||||
return -1;
|
||||
} else if (ssid2) {
|
||||
wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
|
||||
write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
|
||||
return -1;
|
||||
} else {
|
||||
if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
|
||||
return -1;
|
||||
@ -2134,7 +2281,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
char fname[255];
|
||||
FILE *f;
|
||||
struct osu_data *osu = NULL, *last = NULL;
|
||||
size_t osu_count, i, j;
|
||||
size_t osu_count = 0, i, j;
|
||||
int ret;
|
||||
|
||||
write_summary(ctx, "OSU provider selection");
|
||||
@ -2229,8 +2376,12 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
|
||||
"SSID: %s<br>\n",
|
||||
last->bssid, last->osu_ssid);
|
||||
if (last->osu_ssid2[0])
|
||||
fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
|
||||
if (last->osu_nai[0])
|
||||
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
|
||||
if (last->osu_nai2[0])
|
||||
fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
|
||||
fprintf(f, "URL: %s<br>\n"
|
||||
"methods:%s%s<br>\n"
|
||||
"</small></p>\n",
|
||||
@ -2257,6 +2408,8 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
ret = 0;
|
||||
wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
|
||||
wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
|
||||
if (last->osu_ssid2[0])
|
||||
wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
|
||||
wpa_printf(MSG_INFO, "URL: %s", last->url);
|
||||
write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
|
||||
ret, last->bssid, last->osu_ssid, last->url);
|
||||
@ -2311,10 +2464,13 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
"No supported OSU provisioning method");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (connect)
|
||||
} else if (connect) {
|
||||
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
|
||||
last->osu_ssid2,
|
||||
last->url, last->methods,
|
||||
no_prod_assoc, last->osu_nai);
|
||||
no_prod_assoc, last->osu_nai,
|
||||
last->osu_nai2);
|
||||
}
|
||||
} else
|
||||
ret = -1;
|
||||
|
||||
@ -2346,15 +2502,7 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Allow processes running with Group ID as AID_WIFI
|
||||
* to read/write files from osu-info directory
|
||||
*/
|
||||
if (chown(fname, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
|
||||
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
|
||||
if (wpa_command(ifname, buf) < 0) {
|
||||
@ -2920,24 +3068,17 @@ static int init_ctx(struct hs20_osu_client *ctx)
|
||||
return -1;
|
||||
|
||||
devinfo = node_from_file(ctx->xml, "devinfo.xml");
|
||||
if (!devinfo) {
|
||||
wpa_printf(MSG_ERROR, "devinfo.xml not found");
|
||||
return -1;
|
||||
}
|
||||
if (devinfo) {
|
||||
devid = get_node(ctx->xml, devinfo, "DevId");
|
||||
if (devid) {
|
||||
char *tmp = xml_node_get_text(ctx->xml, devid);
|
||||
|
||||
devid = get_node(ctx->xml, devinfo, "DevId");
|
||||
if (devid) {
|
||||
char *tmp = xml_node_get_text(ctx->xml, devid);
|
||||
if (tmp) {
|
||||
ctx->devid = os_strdup(tmp);
|
||||
xml_node_get_text_free(ctx->xml, tmp);
|
||||
if (tmp) {
|
||||
ctx->devid = os_strdup(tmp);
|
||||
xml_node_get_text_free(ctx->xml, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
xml_node_free(ctx->xml, devinfo);
|
||||
|
||||
if (ctx->devid == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
|
||||
return -1;
|
||||
xml_node_free(ctx->xml, devinfo);
|
||||
}
|
||||
|
||||
ctx->http = http_init_ctx(ctx, ctx->xml);
|
||||
@ -3040,7 +3181,7 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
|
||||
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -3057,6 +3198,9 @@ int main(int argc, char *argv[])
|
||||
case 'N':
|
||||
no_prod_assoc = 1;
|
||||
break;
|
||||
case 'o':
|
||||
ctx.osu_ssid = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
friendly_name = optarg;
|
||||
break;
|
||||
|
@ -47,6 +47,7 @@ struct hs20_osu_client {
|
||||
int client_cert_present;
|
||||
char **server_dnsname;
|
||||
size_t server_dnsname_count;
|
||||
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
|
||||
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
|
||||
unsigned long int workarounds;
|
||||
};
|
||||
|
@ -260,7 +260,7 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
static void acs_cleanup(struct hostapd_iface *iface)
|
||||
void acs_cleanup(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
@ -314,7 +314,7 @@ acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
|
||||
|
||||
/* TODO: figure out the best multiplier for noise floor base */
|
||||
factor = pow(10, survey->nf / 5.0L) +
|
||||
(busy / total) *
|
||||
(total ? (busy / total) : 0) *
|
||||
pow(2, pow(10, (long double) survey->nf / 10.0L) -
|
||||
pow(10, (long double) min_nf / 10.0L));
|
||||
|
||||
@ -331,10 +331,8 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
long double int_factor = 0;
|
||||
unsigned count = 0;
|
||||
|
||||
if (dl_list_empty(&chan->survey_list))
|
||||
return;
|
||||
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
if (dl_list_empty(&chan->survey_list) ||
|
||||
(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
return;
|
||||
|
||||
chan->interference_factor = 0;
|
||||
@ -359,9 +357,8 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
(unsigned long) survey->channel_time_rx);
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
chan->interference_factor /= count;
|
||||
if (count)
|
||||
chan->interference_factor /= count;
|
||||
}
|
||||
|
||||
|
||||
@ -450,13 +447,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
|
||||
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++;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
acs_survey_list_is_sufficient(chan))
|
||||
valid++;
|
||||
}
|
||||
|
||||
/* We need at least survey data for one channel */
|
||||
@ -466,13 +459,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
|
||||
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;
|
||||
return !dl_list_empty(&chan->survey_list) &&
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
acs_survey_list_is_sufficient(chan);
|
||||
}
|
||||
|
||||
|
||||
@ -788,10 +777,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
|
||||
|
||||
static int acs_study_options(struct hostapd_iface *iface)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = acs_study_survey_based(iface);
|
||||
if (err == 0)
|
||||
if (acs_study_survey_based(iface) == 0)
|
||||
return 0;
|
||||
|
||||
/* TODO: If no surveys are available/sufficient this is a good
|
||||
@ -920,14 +906,11 @@ static int acs_request_scan(struct hostapd_iface *iface)
|
||||
|
||||
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)
|
||||
if (hostapd_drv_do_acs(iface->bss[0]))
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
}
|
||||
@ -937,8 +920,7 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
|
||||
acs_cleanup(iface);
|
||||
|
||||
err = acs_request_scan(iface);
|
||||
if (err < 0)
|
||||
if (acs_request_scan(iface) < 0)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ACS);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifdef CONFIG_ACS
|
||||
|
||||
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
|
||||
void acs_cleanup(struct hostapd_iface *iface);
|
||||
|
||||
#else /* CONFIG_ACS */
|
||||
|
||||
@ -22,6 +23,10 @@ static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
}
|
||||
|
||||
static inline void acs_cleanup(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
#endif /* ACS_H */
|
||||
|
@ -10,9 +10,11 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "common/dhcp.h"
|
||||
#include "eap_common/eap_wsc_common.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "wpa_auth.h"
|
||||
@ -36,6 +38,10 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES
|
||||
#define DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES 0
|
||||
#endif /* DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES */
|
||||
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
{
|
||||
dl_list_init(&bss->anqp_elem);
|
||||
@ -55,6 +61,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
|
||||
bss->wpa_group_rekey = 600;
|
||||
bss->wpa_gmk_rekey = 86400;
|
||||
bss->wpa_group_update_count = 4;
|
||||
bss->wpa_pairwise_update_count = 4;
|
||||
bss->wpa_disable_eapol_key_retries =
|
||||
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
bss->wpa_pairwise = WPA_CIPHER_TKIP;
|
||||
bss->wpa_group = WPA_CIPHER_TKIP;
|
||||
@ -88,13 +98,39 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
/* Set to -1 as defaults depends on HT in setup */
|
||||
bss->wmm_enabled = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
bss->ft_over_ds = 1;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
bss->rkh_pos_timeout = 86400;
|
||||
bss->rkh_neg_timeout = 60;
|
||||
bss->rkh_pull_timeout = 1000;
|
||||
bss->rkh_pull_retries = 4;
|
||||
bss->r0_key_lifetime = 1209600;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
bss->radius_das_time_window = 300;
|
||||
|
||||
bss->sae_anti_clogging_threshold = 5;
|
||||
bss->sae_sync = 5;
|
||||
|
||||
bss->gas_frag_limit = 1400;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
dl_list_init(&bss->fils_realms);
|
||||
bss->fils_hlp_wait_time = 30;
|
||||
bss->dhcp_server_port = DHCP_SERVER_PORT;
|
||||
bss->dhcp_relay_port = DHCP_SERVER_PORT;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
bss->broadcast_deauth = 1;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
bss->mbo_cell_data_conn_pref = -1;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
/* Disable TLS v1.3 by default for now to avoid interoperability issue.
|
||||
* This can be enabled by default once the implementation has been fully
|
||||
* completed and tested with other implementations. */
|
||||
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
|
||||
}
|
||||
|
||||
|
||||
@ -192,6 +228,11 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->acs_num_scans = 5;
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
/* The third octet of the country string uses an ASCII space character
|
||||
* by default to indicate that the regulations encompass all
|
||||
* environments for the current frequency band in the country. */
|
||||
conf->country[2] = ' ';
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -329,13 +370,7 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
|
||||
ssid->wpa_psk->group = 1;
|
||||
}
|
||||
|
||||
if (ssid->wpa_psk_file) {
|
||||
if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
|
||||
&conf->ssid))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return hostapd_config_read_wpa_psk(ssid->wpa_psk_file, &conf->ssid);
|
||||
}
|
||||
|
||||
|
||||
@ -380,10 +415,23 @@ void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
|
||||
hostapd_config_free_radius_attr(user->accept_attr);
|
||||
os_free(user->identity);
|
||||
bin_clear_free(user->password, user->password_len);
|
||||
bin_clear_free(user->salt, user->salt_len);
|
||||
os_free(user);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
|
||||
{
|
||||
struct hostapd_eap_user *prev_user;
|
||||
|
||||
while (user) {
|
||||
prev_user = user;
|
||||
user = user->next;
|
||||
hostapd_config_free_eap_user(prev_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
|
||||
{
|
||||
int i;
|
||||
@ -420,10 +468,38 @@ static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_fils_realms(struct hostapd_bss_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_FILS
|
||||
struct fils_realm *realm;
|
||||
|
||||
while ((realm = dl_list_first(&conf->fils_realms, struct fils_realm,
|
||||
list))) {
|
||||
dl_list_del(&realm->list);
|
||||
os_free(realm);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct sae_password_entry *pw, *tmp;
|
||||
|
||||
pw = conf->sae_passwords;
|
||||
conf->sae_passwords = NULL;
|
||||
while (pw) {
|
||||
tmp = pw;
|
||||
pw = pw->next;
|
||||
str_clear_free(tmp->password);
|
||||
os_free(tmp->identifier);
|
||||
os_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct hostapd_eap_user *user, *prev_user;
|
||||
|
||||
if (conf == NULL)
|
||||
return;
|
||||
|
||||
@ -436,12 +512,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->ssid.vlan_tagged_interface);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
user = conf->eap_user;
|
||||
while (user) {
|
||||
prev_user = user;
|
||||
user = user->next;
|
||||
hostapd_config_free_eap_user(prev_user);
|
||||
}
|
||||
hostapd_config_free_eap_users(conf->eap_user);
|
||||
os_free(conf->eap_user_sqlite);
|
||||
|
||||
os_free(conf->eap_req_id_text);
|
||||
@ -477,7 +548,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
hostapd_config_free_vlan(conf);
|
||||
os_free(conf->time_zone);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
{
|
||||
struct ft_remote_r0kh *r0kh, *r0kh_prev;
|
||||
struct ft_remote_r1kh *r1kh, *r1kh_prev;
|
||||
@ -498,7 +569,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(r1kh_prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
os_free(conf->wps_pin_requests);
|
||||
@ -530,6 +601,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
os_free(conf->roaming_consortium);
|
||||
os_free(conf->venue_name);
|
||||
os_free(conf->venue_url);
|
||||
os_free(conf->nai_realm_data);
|
||||
os_free(conf->network_auth_type);
|
||||
os_free(conf->anqp_3gpp_cell_net);
|
||||
@ -559,17 +631,30 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(p->icons[j]);
|
||||
os_free(p->icons);
|
||||
os_free(p->osu_nai);
|
||||
os_free(p->osu_nai2);
|
||||
os_free(p->service_desc);
|
||||
}
|
||||
os_free(conf->hs20_osu_providers);
|
||||
}
|
||||
if (conf->hs20_operator_icon) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < conf->hs20_operator_icon_count; i++)
|
||||
os_free(conf->hs20_operator_icon[i]);
|
||||
os_free(conf->hs20_operator_icon);
|
||||
}
|
||||
os_free(conf->subscr_remediation_url);
|
||||
os_free(conf->t_c_filename);
|
||||
os_free(conf->t_c_server_url);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
wpabuf_free(conf->vendor_elements);
|
||||
wpabuf_free(conf->assocresp_elements);
|
||||
|
||||
os_free(conf->sae_groups);
|
||||
#ifdef CONFIG_OWE
|
||||
os_free(conf->owe_groups);
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
os_free(conf->wowlan_triggers);
|
||||
|
||||
@ -577,11 +662,22 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpabuf_free(conf->own_ie_override);
|
||||
wpabuf_free(conf->sae_commit_override);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_free(conf->no_probe_resp_if_seen_on);
|
||||
os_free(conf->no_auth_if_seen_on);
|
||||
|
||||
hostapd_config_free_fils_realms(conf);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
os_free(conf->dpp_connector);
|
||||
wpabuf_free(conf->dpp_netaccesskey);
|
||||
wpabuf_free(conf->dpp_csign);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
hostapd_config_free_sae_passwords(conf);
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
|
||||
@ -802,7 +898,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
|
||||
(bss->nas_identifier == NULL ||
|
||||
os_strlen(bss->nas_identifier) < 1 ||
|
||||
@ -812,7 +908,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
"string");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (full_config && conf->ieee80211n &&
|
||||
@ -848,6 +944,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
|
||||
}
|
||||
|
||||
if (full_config && conf->ieee80211ac && 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_11ac = 1;
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
@ -866,7 +972,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
|
||||
if (full_config && bss->wps_state && bss->wpa &&
|
||||
(!(bss->wpa & 2) ||
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 |
|
||||
WPA_CIPHER_GCMP_256)))) {
|
||||
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
|
||||
"WPA2/CCMP/GCMP forced WPS to be disabled");
|
||||
bss->wps_state = 0;
|
||||
@ -976,8 +1084,15 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
|
||||
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 (bss->group_cipher)
|
||||
bss->wpa_group = bss->group_cipher;
|
||||
else
|
||||
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
|
||||
bss->wpa_pairwise,
|
||||
bss->rsn_pairwise);
|
||||
if (!bss->wpa_group_rekey_set)
|
||||
bss->wpa_group_rekey = bss->wpa_group == WPA_CIPHER_TKIP ?
|
||||
600 : 86400;
|
||||
|
||||
if (full_config) {
|
||||
bss->radius->auth_server = bss->radius->auth_servers;
|
||||
|
@ -160,6 +160,8 @@ struct hostapd_eap_user {
|
||||
} methods[EAP_MAX_METHODS];
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
u8 *salt;
|
||||
size_t salt_len; /* non-zero when password is salted */
|
||||
int phase2;
|
||||
int force_version;
|
||||
unsigned int wildcard_prefix:1;
|
||||
@ -169,6 +171,7 @@ struct hostapd_eap_user {
|
||||
unsigned int macacl:1;
|
||||
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||
struct hostapd_radius_attr *accept_attr;
|
||||
u32 t_c_timestamp;
|
||||
};
|
||||
|
||||
struct hostapd_radius_attr {
|
||||
@ -201,6 +204,12 @@ struct hostapd_lang_string {
|
||||
u8 name[252];
|
||||
};
|
||||
|
||||
struct hostapd_venue_url {
|
||||
u8 venue_number;
|
||||
u8 url_len;
|
||||
u8 url[254];
|
||||
};
|
||||
|
||||
#define MAX_NAI_REALMS 10
|
||||
#define MAX_NAI_REALMLEN 255
|
||||
#define MAX_NAI_EAP_METHODS 5
|
||||
@ -224,6 +233,18 @@ struct anqp_element {
|
||||
struct wpabuf *payload;
|
||||
};
|
||||
|
||||
struct fils_realm {
|
||||
struct dl_list list;
|
||||
u8 hash[2];
|
||||
char realm[];
|
||||
};
|
||||
|
||||
struct sae_password_entry {
|
||||
struct sae_password_entry *next;
|
||||
char *password;
|
||||
char *identifier;
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_bss_config - Per-BSS configuration
|
||||
@ -242,7 +263,8 @@ struct hostapd_bss_config {
|
||||
int max_num_sta; /* maximum number of STAs in station table */
|
||||
|
||||
int dtim_period;
|
||||
int bss_load_update_period;
|
||||
unsigned int bss_load_update_period;
|
||||
unsigned int chan_util_avg_period;
|
||||
|
||||
int ieee802_1x; /* use IEEE 802.1X */
|
||||
int eapol_version;
|
||||
@ -287,7 +309,7 @@ struct hostapd_bss_config {
|
||||
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
|
||||
* frames */
|
||||
|
||||
enum {
|
||||
enum macaddr_acl {
|
||||
ACCEPT_UNLESS_DENIED = 0,
|
||||
DENY_UNLESS_ACCEPTED = 1,
|
||||
USE_EXTERNAL_RADIUS_AUTH = 2
|
||||
@ -319,27 +341,37 @@ struct hostapd_bss_config {
|
||||
PSK_RADIUS_REQUIRED = 2
|
||||
} wpa_psk_radius;
|
||||
int wpa_pairwise;
|
||||
int group_cipher; /* wpa_group value override from configuation */
|
||||
int wpa_group;
|
||||
int wpa_group_rekey;
|
||||
int wpa_group_rekey_set;
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int wpa_ptk_rekey;
|
||||
u32 wpa_group_update_count;
|
||||
u32 wpa_pairwise_update_count;
|
||||
int wpa_disable_eapol_key_retries;
|
||||
int rsn_pairwise;
|
||||
int rsn_preauth;
|
||||
char *rsn_preauth_interfaces;
|
||||
int peerkey;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
/* IEEE 802.11r - Fast BSS Transition */
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r1_key_holder[FT_R1KH_ID_LEN];
|
||||
u32 r0_key_lifetime;
|
||||
u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
|
||||
int rkh_pos_timeout;
|
||||
int rkh_neg_timeout;
|
||||
int rkh_pull_timeout; /* ms */
|
||||
int rkh_pull_retries;
|
||||
u32 reassociation_deadline;
|
||||
struct ft_remote_r0kh *r0kh_list;
|
||||
struct ft_remote_r1kh *r1kh_list;
|
||||
int pmk_r1_push;
|
||||
int ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int ft_psk_generate_local;
|
||||
int r1_max_key_lifetime;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
@ -353,6 +385,7 @@ struct hostapd_bss_config {
|
||||
char *private_key_passwd;
|
||||
int check_crl;
|
||||
unsigned int tls_session_lifetime;
|
||||
unsigned int tls_flags;
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
char *dh_file;
|
||||
@ -464,6 +497,7 @@ struct hostapd_bss_config {
|
||||
int time_advertisement;
|
||||
char *time_zone;
|
||||
int wnm_sleep_mode;
|
||||
int wnm_sleep_mode_no_keys;
|
||||
int bss_transition;
|
||||
|
||||
/* IEEE 802.11u - Interworking */
|
||||
@ -486,6 +520,10 @@ struct hostapd_bss_config {
|
||||
unsigned int venue_name_count;
|
||||
struct hostapd_lang_string *venue_name;
|
||||
|
||||
/* Venue URL duples */
|
||||
unsigned int venue_url_count;
|
||||
struct hostapd_venue_url *venue_url;
|
||||
|
||||
/* IEEE 802.11u - Network Authentication Type */
|
||||
u8 *network_auth_type;
|
||||
size_t network_auth_type_len;
|
||||
@ -508,7 +546,7 @@ struct hostapd_bss_config {
|
||||
struct dl_list anqp_elem; /* list of struct anqp_element */
|
||||
|
||||
u16 gas_comeback_delay;
|
||||
int gas_frag_limit;
|
||||
size_t gas_frag_limit;
|
||||
int gas_address3;
|
||||
|
||||
u8 qos_map_set[16 + 2 * 21];
|
||||
@ -547,13 +585,20 @@ struct hostapd_bss_config {
|
||||
char **icons;
|
||||
size_t icons_count;
|
||||
char *osu_nai;
|
||||
char *osu_nai2;
|
||||
unsigned int service_desc_count;
|
||||
struct hostapd_lang_string *service_desc;
|
||||
} *hs20_osu_providers, *last_osu;
|
||||
size_t hs20_osu_providers_count;
|
||||
size_t hs20_osu_providers_nai_count;
|
||||
char **hs20_operator_icon;
|
||||
size_t hs20_operator_icon_count;
|
||||
unsigned int hs20_deauth_req_timeout;
|
||||
char *subscr_remediation_url;
|
||||
u8 subscr_remediation_method;
|
||||
char *t_c_filename;
|
||||
u32 t_c_timestamp;
|
||||
char *t_c_server_url;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
|
||||
@ -566,7 +611,10 @@ struct hostapd_bss_config {
|
||||
struct wpabuf *assocresp_elements;
|
||||
|
||||
unsigned int sae_anti_clogging_threshold;
|
||||
unsigned int sae_sync;
|
||||
int sae_require_mfp;
|
||||
int *sae_groups;
|
||||
struct sae_password_entry *sae_passwords;
|
||||
|
||||
char *wowlan_triggers; /* Wake-on-WLAN triggers */
|
||||
|
||||
@ -574,6 +622,8 @@ struct hostapd_bss_config {
|
||||
u8 bss_load_test[5];
|
||||
u8 bss_load_test_set;
|
||||
struct wpabuf *own_ie_override;
|
||||
int sae_reflection_attack;
|
||||
struct wpabuf *sae_commit_override;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define MESH_ENABLED BIT(0)
|
||||
@ -591,12 +641,71 @@ struct hostapd_bss_config {
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
int mbo_enabled;
|
||||
/**
|
||||
* oce - Enable OCE in AP and/or STA-CFON mode
|
||||
* - BIT(0) is Reserved
|
||||
* - Set BIT(1) to enable OCE in STA-CFON mode
|
||||
* - Set BIT(2) to enable OCE in AP mode
|
||||
*/
|
||||
unsigned int oce;
|
||||
int mbo_cell_data_conn_pref;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
int ftm_responder;
|
||||
int ftm_initiator;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
int fils_cache_id_set;
|
||||
struct dl_list fils_realms; /* list of struct fils_realm */
|
||||
int fils_dh_group;
|
||||
struct hostapd_ip_addr dhcp_server;
|
||||
int dhcp_rapid_commit_proxy;
|
||||
unsigned int fils_hlp_wait_time;
|
||||
u16 dhcp_server_port;
|
||||
u16 dhcp_relay_port;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
int multicast_to_unicast;
|
||||
|
||||
int broadcast_deauth;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
char *dpp_connector;
|
||||
struct wpabuf *dpp_netaccesskey;
|
||||
unsigned int dpp_netaccesskey_expiry;
|
||||
struct wpabuf *dpp_csign;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
macaddr owe_transition_bssid;
|
||||
u8 owe_transition_ssid[SSID_MAX_LEN];
|
||||
size_t owe_transition_ssid_len;
|
||||
char owe_transition_ifname[IFNAMSIZ + 1];
|
||||
int *owe_groups;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
int coloc_intf_reporting;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct he_phy_capabilities_info - HE PHY capabilities
|
||||
*/
|
||||
struct he_phy_capabilities_info {
|
||||
Boolean he_su_beamformer;
|
||||
Boolean he_su_beamformee;
|
||||
Boolean he_mu_beamformer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct he_operation - HE operation
|
||||
*/
|
||||
struct he_operation {
|
||||
u8 he_bss_color;
|
||||
u8 he_default_pe_duration;
|
||||
u8 he_twt_required;
|
||||
u8 he_rts_threshold;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_config - Per-radio interface configuration
|
||||
@ -612,6 +721,7 @@ struct hostapd_config {
|
||||
u8 channel;
|
||||
u8 acs;
|
||||
struct wpa_freq_range_list acs_ch_list;
|
||||
int acs_exclude_dfs;
|
||||
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||
enum {
|
||||
LONG_PREAMBLE = 0,
|
||||
@ -620,6 +730,8 @@ struct hostapd_config {
|
||||
|
||||
int *supported_rates;
|
||||
int *basic_rates;
|
||||
unsigned int beacon_rate;
|
||||
enum beacon_rate_type rate_type;
|
||||
|
||||
const struct wpa_driver_ops *driver;
|
||||
char *driver_params;
|
||||
@ -635,6 +747,9 @@ struct hostapd_config {
|
||||
* ' ' (ascii 32): all environments
|
||||
* 'O': Outdoor environemnt only
|
||||
* 'I': Indoor environment only
|
||||
* 'X': Used with noncountry entity ("XXX")
|
||||
* 0x00..0x31: identifying IEEE 802.11 standard
|
||||
* Annex E table (0x04 = global table)
|
||||
*/
|
||||
|
||||
int ieee80211d;
|
||||
@ -675,6 +790,7 @@ struct hostapd_config {
|
||||
u8 vht_oper_chwidth;
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
u8 ht40_plus_minus_allowed;
|
||||
|
||||
/* Use driver-generated interface addresses when adding multiple BSSs */
|
||||
u8 use_driver_iface_addr;
|
||||
@ -707,6 +823,18 @@ struct hostapd_config {
|
||||
|
||||
struct wpabuf *lci;
|
||||
struct wpabuf *civic;
|
||||
int stationary_ap;
|
||||
|
||||
int ieee80211ax;
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
struct he_phy_capabilities_info he_phy_capab;
|
||||
struct he_operation he_op;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* VHT enable/disable config from CHAN_SWITCH */
|
||||
#define CH_SWITCH_VHT_ENABLED BIT(0)
|
||||
#define CH_SWITCH_VHT_DISABLED BIT(1)
|
||||
unsigned int ch_switch_vht_config;
|
||||
};
|
||||
|
||||
|
||||
@ -714,6 +842,7 @@ int hostapd_mac_comp(const void *a, const void *b);
|
||||
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_free_eap_users(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);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ap_config.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "hs20.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "ap_drv_ops.h"
|
||||
|
||||
|
||||
@ -99,6 +100,13 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
pos = hostapd_eid_fils_indic(hapd, buf, 0);
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
|
||||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
|
||||
goto fail;
|
||||
@ -168,7 +176,8 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled) {
|
||||
if (hapd->conf->mbo_enabled ||
|
||||
OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
|
||||
pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0 ||
|
||||
@ -177,6 +186,13 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
add_buf(&beacon, hapd->conf->vendor_elements);
|
||||
add_buf(&proberesp, hapd->conf->vendor_elements);
|
||||
add_buf(&assocresp, hapd->conf->assocresp_elements);
|
||||
@ -340,10 +356,44 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 seq, u16 status, const u8 *ie, size_t len)
|
||||
{
|
||||
struct wpa_driver_sta_auth_params params;
|
||||
#ifdef CONFIG_FILS
|
||||
struct sta_info *sta;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
|
||||
seq, status, ie, len);
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for sta_auth processing",
|
||||
MAC2STR(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
|
||||
params.fils_auth = 1;
|
||||
wpa_auth_get_fils_aead_params(sta->wpa_sm, params.fils_anonce,
|
||||
params.fils_snonce,
|
||||
params.fils_kek,
|
||||
¶ms.fils_kek_len);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
params.own_addr = hapd->own_addr;
|
||||
params.addr = addr;
|
||||
params.seq = seq;
|
||||
params.status = status;
|
||||
params.ie = ie;
|
||||
params.len = len;
|
||||
|
||||
return hapd->driver->sta_auth(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
@ -554,13 +604,13 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags)
|
||||
u16 *flags, u8 *dfs_domain)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->get_hw_feature_data == NULL)
|
||||
return NULL;
|
||||
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
||||
flags);
|
||||
flags, dfs_domain);
|
||||
}
|
||||
|
||||
|
||||
@ -694,6 +744,15 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC))
|
||||
bssid = wildcard_bssid;
|
||||
} else if (is_broadcast_ether_addr(dst) &&
|
||||
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
|
||||
/*
|
||||
* The only current use case of Public Action frames with
|
||||
* broadcast destination address is DPP PKEX. That case is
|
||||
* directing all devices and not just the STAs within the BSS,
|
||||
* so have to use the wildcard BSSID value.
|
||||
*/
|
||||
bssid = wildcard_bssid;
|
||||
}
|
||||
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
|
||||
hapd->own_addr, bssid, data, len, 0);
|
||||
@ -774,7 +833,9 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
if ((acs_ch_list_all ||
|
||||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan)) &&
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
!(hapd->iface->conf->acs_exclude_dfs &&
|
||||
(chan->flag & HOSTAPD_CHAN_RADAR)))
|
||||
int_array_add_unique(freq_list, chan->freq);
|
||||
}
|
||||
}
|
||||
@ -829,6 +890,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan))
|
||||
continue;
|
||||
if (hapd->iface->conf->acs_exclude_dfs &&
|
||||
(chan->flag & HOSTAPD_CHAN_RADAR))
|
||||
continue;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
|
||||
channels[num_channels++] = chan->chan;
|
||||
int_array_add_unique(&freq_list, chan->freq);
|
||||
|
@ -72,7 +72,7 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time);
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags);
|
||||
u16 *flags, u8 *dfs_domain);
|
||||
int hostapd_driver_commit(struct hostapd_data *hapd);
|
||||
int hostapd_drv_none(struct hostapd_data *hapd);
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
@ -103,6 +103,14 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
|
||||
unsigned int freq,
|
||||
unsigned int wait, const u8 *dst,
|
||||
const u8 *data, size_t len);
|
||||
static inline void
|
||||
hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->send_action_cancel_wait ||
|
||||
!hapd->drv_priv)
|
||||
return;
|
||||
hapd->driver->send_action_cancel_wait(hapd->drv_priv);
|
||||
}
|
||||
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 auth_alg);
|
||||
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -274,8 +282,9 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
|
||||
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;
|
||||
if (hapd->driver == NULL || hapd->driver->switch_channel == NULL ||
|
||||
hapd->drv_priv == NULL)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->switch_channel(hapd->drv_priv, settings);
|
||||
}
|
||||
|
@ -57,7 +57,11 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
|
||||
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK &&
|
||||
!(sta->flags & WLAN_STA_MFP))
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
@ -105,7 +109,10 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-ASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
@ -130,7 +137,10 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-REASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
|
@ -71,19 +71,26 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
}
|
||||
|
||||
if (eap_user->password) {
|
||||
user->password = os_malloc(eap_user->password_len);
|
||||
user->password = os_memdup(eap_user->password,
|
||||
eap_user->password_len);
|
||||
if (user->password == NULL)
|
||||
goto out;
|
||||
os_memcpy(user->password, eap_user->password,
|
||||
eap_user->password_len);
|
||||
user->password_len = eap_user->password_len;
|
||||
user->password_hash = eap_user->password_hash;
|
||||
if (eap_user->salt && eap_user->salt_len) {
|
||||
user->salt = os_memdup(eap_user->salt,
|
||||
eap_user->salt_len);
|
||||
if (!user->salt)
|
||||
goto out;
|
||||
user->salt_len = eap_user->salt_len;
|
||||
}
|
||||
}
|
||||
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;
|
||||
user->t_c_timestamp = eap_user->t_c_timestamp;
|
||||
rv = 0;
|
||||
|
||||
out:
|
||||
@ -129,10 +136,12 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#ifdef CONFIG_HS20
|
||||
srv.subscr_remediation_url = conf->subscr_remediation_url;
|
||||
srv.subscr_remediation_method = conf->subscr_remediation_method;
|
||||
srv.t_c_server_url = conf->t_c_server_url;
|
||||
#endif /* CONFIG_HS20 */
|
||||
srv.erp = conf->eap_server_erp;
|
||||
srv.erp_domain = conf->erp_domain;
|
||||
srv.tls_session_lifetime = conf->tls_session_lifetime;
|
||||
srv.tls_flags = conf->tls_flags;
|
||||
|
||||
hapd->radius_srv = radius_server_init(&srv);
|
||||
if (hapd->radius_srv == NULL) {
|
||||
@ -146,6 +155,40 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#endif /* RADIUS_SERVER */
|
||||
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
static void authsrv_tls_event(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data)
|
||||
{
|
||||
switch (ev) {
|
||||
case TLS_CERT_CHAIN_SUCCESS:
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success");
|
||||
break;
|
||||
case TLS_CERT_CHAIN_FAILURE:
|
||||
wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
|
||||
data->cert_fail.reason,
|
||||
data->cert_fail.depth,
|
||||
data->cert_fail.subject,
|
||||
data->cert_fail.reason_txt);
|
||||
break;
|
||||
case TLS_PEER_CERTIFICATE:
|
||||
wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s",
|
||||
data->peer_cert.depth,
|
||||
data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
|
||||
data->peer_cert.subject);
|
||||
break;
|
||||
case TLS_ALERT:
|
||||
if (data->alert.is_local)
|
||||
wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s",
|
||||
data->alert.description);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
|
||||
data->alert.description);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
|
||||
int authsrv_init(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
@ -157,6 +200,9 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
|
||||
os_memset(&conf, 0, sizeof(conf));
|
||||
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
conf.tls_flags = hapd->conf->tls_flags;
|
||||
conf.event_cb = authsrv_tls_event;
|
||||
conf.cb_ctx = hapd;
|
||||
hapd->ssl_ctx = tls_init(&conf);
|
||||
if (hapd->ssl_ctx == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "wps/wps_defs.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "hostapd.h"
|
||||
@ -30,6 +31,7 @@
|
||||
#include "hs20.h"
|
||||
#include "dfs.h"
|
||||
#include "taxonomy.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
@ -392,7 +394,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
2 + sizeof(struct ieee80211_vht_operation);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
buflen += hostapd_mbo_ie_len(hapd);
|
||||
buflen += hostapd_eid_owe_trans_len(hapd);
|
||||
|
||||
resp = os_zalloc(buflen);
|
||||
if (resp == NULL)
|
||||
@ -443,8 +453,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
pos = hostapd_eid_ext_supp_rates(hapd, pos);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
/* RSN, MDIE */
|
||||
if (hapd->conf->wpa != WPA_PROTO_WPA)
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
|
||||
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
|
||||
|
||||
@ -491,10 +502,26 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_txpower_envelope(hapd, pos);
|
||||
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
pos = hostapd_eid_fils_indic(hapd, pos, 0);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
pos = hostapd_eid_he_capab(hapd, pos);
|
||||
pos = hostapd_eid_he_operation(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->conf->vendor_vht)
|
||||
pos = hostapd_eid_vendor_vht(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA)
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
pos = hostapd_eid_wmm(hapd, pos);
|
||||
|
||||
@ -526,6 +553,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -618,7 +646,7 @@ static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
@ -628,6 +656,7 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
dl_list_del(&info->list);
|
||||
dl_list_add_tail(&iface->sta_seen, &info->list);
|
||||
os_get_reltime(&info->last_seen);
|
||||
info->ssi_signal = ssi_signal;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -637,6 +666,7 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
return;
|
||||
os_memcpy(info->addr, addr, ETH_ALEN);
|
||||
os_get_reltime(&info->last_seen);
|
||||
info->ssi_signal = ssi_signal;
|
||||
|
||||
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
|
||||
/* Expire oldest entry to make room for a new one */
|
||||
@ -707,14 +737,30 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
int ret;
|
||||
u16 csa_offs[2];
|
||||
size_t csa_offs_len;
|
||||
u32 session_timeout, acct_interim_interval;
|
||||
struct vlan_description vlan_id;
|
||||
struct hostapd_sta_wpa_psk_short *psk = NULL;
|
||||
char *identity = NULL;
|
||||
char *radius_cui = NULL;
|
||||
|
||||
if (len < IEEE80211_HDRLEN)
|
||||
return;
|
||||
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
|
||||
if (hapd->iconf->track_sta_max_num)
|
||||
sta_track_add(hapd->iface, mgmt->sa);
|
||||
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
|
||||
ie_len = len - IEEE80211_HDRLEN;
|
||||
|
||||
ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
|
||||
&session_timeout,
|
||||
&acct_interim_interval, &vlan_id,
|
||||
&psk, &identity, &radius_cui, 1);
|
||||
if (ret == HOSTAPD_ACL_REJECT) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Ignore Probe Request frame from " MACSTR
|
||||
" due to ACL reject ", MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
|
||||
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
|
||||
mgmt->sa, mgmt->da, mgmt->bssid,
|
||||
@ -909,6 +955,9 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
|
||||
" signal=%d", MAC2STR(mgmt->sa), ssi_signal);
|
||||
|
||||
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
|
||||
&resp_len);
|
||||
if (resp == NULL)
|
||||
@ -1033,7 +1082,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
tail_len += hostapd_mbo_ie_len(hapd);
|
||||
tail_len += hostapd_eid_owe_trans_len(hapd);
|
||||
|
||||
tailpos = tail = os_malloc(tail_len);
|
||||
if (head == NULL || tail == NULL) {
|
||||
@ -1100,9 +1157,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
/* RSN, MDIE */
|
||||
if (hapd->conf->wpa != WPA_PROTO_WPA)
|
||||
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 -
|
||||
@ -1155,10 +1214,28 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
|
||||
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_operation(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->conf->vendor_vht)
|
||||
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA)
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
tailpos = hostapd_eid_wmm(hapd, tailpos);
|
||||
|
||||
@ -1189,6 +1266,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
|
||||
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
|
||||
tail + tail_len - tailpos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -1211,6 +1290,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->dtim_period = hapd->conf->dtim_period;
|
||||
params->beacon_int = hapd->iconf->beacon_int;
|
||||
params->basic_rates = hapd->iface->basic_rates;
|
||||
params->beacon_rate = hapd->iconf->beacon_rate;
|
||||
params->rate_type = hapd->iconf->rate_type;
|
||||
params->ssid = hapd->conf->ssid.ssid;
|
||||
params->ssid_len = hapd->conf->ssid.ssid_len;
|
||||
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
|
||||
@ -1274,6 +1355,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->osen = 1;
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
|
||||
params->pbss = hapd->conf->pbss;
|
||||
return 0;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ 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);
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal);
|
||||
void sta_track_del(struct hostapd_sta_info *info);
|
||||
void sta_track_expire(struct hostapd_iface *iface, int force);
|
||||
struct hostapd_data *
|
||||
|
@ -16,11 +16,35 @@
|
||||
#include "beacon.h"
|
||||
|
||||
|
||||
static int get_bss_load_update_timeout(struct hostapd_data *hapd,
|
||||
unsigned int *sec, unsigned int *usec)
|
||||
{
|
||||
unsigned int update_period = hapd->conf->bss_load_update_period;
|
||||
unsigned int beacon_int = hapd->iconf->beacon_int;
|
||||
unsigned int update_timeout;
|
||||
|
||||
if (!update_period || !beacon_int) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
|
||||
update_period, beacon_int);
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_timeout = update_period * beacon_int;
|
||||
|
||||
*sec = ((update_timeout / 1000) * 1024) / 1000;
|
||||
*usec = (update_timeout % 1000) * 1024;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_data;
|
||||
unsigned int sec, usec;
|
||||
int err;
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
|
||||
if (!(hapd->beacon_set_done && hapd->started))
|
||||
return;
|
||||
@ -33,8 +57,24 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
|
||||
ieee802_11_set_beacon(hapd);
|
||||
|
||||
sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
|
||||
usec = (hapd->bss_load_update_timeout % 1000) * 1024;
|
||||
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
|
||||
return;
|
||||
|
||||
if (hapd->conf->chan_util_avg_period) {
|
||||
iface->chan_util_samples_sum += iface->channel_utilization;
|
||||
iface->chan_util_num_sample_periods +=
|
||||
hapd->conf->bss_load_update_period;
|
||||
if (iface->chan_util_num_sample_periods >=
|
||||
hapd->conf->chan_util_avg_period) {
|
||||
iface->chan_util_average =
|
||||
iface->chan_util_samples_sum /
|
||||
(iface->chan_util_num_sample_periods /
|
||||
hapd->conf->bss_load_update_period);
|
||||
iface->chan_util_samples_sum = 0;
|
||||
iface->chan_util_num_sample_periods = 0;
|
||||
}
|
||||
}
|
||||
|
||||
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
|
||||
NULL);
|
||||
}
|
||||
@ -42,17 +82,11 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
|
||||
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)
|
||||
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
|
||||
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;
|
||||
|
@ -26,23 +26,141 @@
|
||||
#include "taxonomy.h"
|
||||
|
||||
|
||||
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
|
||||
size_t curr_len, const u8 *mcs_set)
|
||||
{
|
||||
int ret;
|
||||
size_t len = curr_len;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"ht_mcs_bitmask=");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
/* 77 first bits (+ 3 reserved bits) */
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return curr_len;
|
||||
len += ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
int len = 0;
|
||||
|
||||
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=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
|
||||
"rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
|
||||
"signal=%d\n",
|
||||
data.rx_packets, data.tx_packets,
|
||||
data.rx_bytes, data.tx_bytes, data.inactive_msec);
|
||||
data.rx_bytes, data.tx_bytes, data.inactive_msec,
|
||||
data.signal);
|
||||
if (os_snprintf_error(buflen, ret))
|
||||
return 0;
|
||||
return ret;
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
|
||||
data.current_rx_rate);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
if (data.flags & STA_DRV_DATA_RX_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " mcs %u",
|
||||
data.rx_mcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
|
||||
data.rx_vhtmcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
|
||||
data.rx_vht_nss);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " shortGI");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
|
||||
data.current_tx_rate);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
if (data.flags & STA_DRV_DATA_TX_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " mcs %u",
|
||||
data.tx_mcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
|
||||
data.tx_vhtmcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
|
||||
data.tx_vht_nss);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " shortGI");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
|
||||
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"rx_vht_mcs_map=%04x\n"
|
||||
"tx_vht_mcs_map=%04x\n",
|
||||
le_to_host16(sta->vht_capabilities->
|
||||
vht_supported_mcs_set.rx_map),
|
||||
le_to_host16(sta->vht_capabilities->
|
||||
vht_supported_mcs_set.tx_map));
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
|
||||
len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
|
||||
sta->ht_capabilities->
|
||||
supported_mcs_set);
|
||||
}
|
||||
|
||||
if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"last_ack_signal=%d\n", data.last_ack_rssi);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +294,53 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
}
|
||||
|
||||
if (sta->power_capab) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"min_txpower=%d\n"
|
||||
"max_txpower=%d\n",
|
||||
sta->min_tx_power, sta->max_tx_power);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
"vht_caps_info=0x%08x\n",
|
||||
le_to_host32(sta->vht_capabilities->
|
||||
vht_capabilities_info));
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
"ht_caps_info=0x%04x\n",
|
||||
le_to_host16(sta->ht_capabilities->
|
||||
ht_capabilities_info));
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if (sta->ext_capability &&
|
||||
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
|
||||
len += os_snprintf(buf + len, buflen - len, "ext_capab=");
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
sta->ext_capability + 1,
|
||||
sta->ext_capability[0]);
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
}
|
||||
|
||||
if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"wds_sta_ifname=%s\n", sta->ifname_wds);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -477,7 +642,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
int len = 0, ret;
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
int len = 0, ret, j;
|
||||
size_t i;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
@ -537,13 +703,17 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
"channel=%u\n"
|
||||
"secondary_channel=%d\n"
|
||||
"ieee80211n=%d\n"
|
||||
"ieee80211ac=%d\n",
|
||||
"ieee80211ac=%d\n"
|
||||
"beacon_int=%u\n"
|
||||
"dtim_period=%d\n",
|
||||
iface->conf->channel,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
|
||||
iface->conf->secondary_channel : 0,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n,
|
||||
iface->conf->ieee80211ac &&
|
||||
!hapd->conf->disable_11ac);
|
||||
!hapd->conf->disable_11ac,
|
||||
iface->conf->beacon_int,
|
||||
hapd->conf->dtim_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
@ -551,15 +721,76 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"vht_oper_chwidth=%d\n"
|
||||
"vht_oper_centr_freq_seg0_idx=%d\n"
|
||||
"vht_oper_centr_freq_seg1_idx=%d\n",
|
||||
"vht_oper_centr_freq_seg1_idx=%d\n"
|
||||
"vht_caps_info=%08x\n",
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx);
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx,
|
||||
iface->conf->vht_capab);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
|
||||
u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
|
||||
u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"rx_vht_mcs_map=%04x\n"
|
||||
"tx_vht_mcs_map=%04x\n",
|
||||
rxmap, txmap);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"ht_caps_info=%04x\n",
|
||||
hapd->iconf->ht_capab);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
|
||||
len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
|
||||
mode->mcs_set);
|
||||
}
|
||||
|
||||
if (iface->current_rates && iface->num_rates) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
for (j = 0; j < iface->num_rates; j++) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "%s%02x",
|
||||
j > 0 ? " " : "",
|
||||
iface->current_rates[j].rate / 5);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
for (j = 0; mode && j < mode->num_channels; j++) {
|
||||
if (mode->channels[j].freq == iface->freq) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"max_txpower=%u\n",
|
||||
mode->channels[j].max_tx_power);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
@ -578,6 +809,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (hapd->conf->chan_util_avg_period) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"chan_util_avg=%u\n",
|
||||
iface->chan_util_average);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -639,3 +879,108 @@ void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
wpa_auth_pmksa_flush(hapd->wpa_auth);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
|
||||
{
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
char *pos, *pos2;
|
||||
int akmp = 0, expiration = 0;
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
|
||||
*/
|
||||
|
||||
if (hwaddr_aton(cmd, spa))
|
||||
return -1;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
|
||||
return -1;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos++;
|
||||
|
||||
pos2 = os_strchr(pos, ' ');
|
||||
if (!pos2)
|
||||
return -1;
|
||||
pmk_len = (pos2 - pos) / 2;
|
||||
if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
|
||||
hexstr2bin(pos, pmk, pmk_len) < 0)
|
||||
return -1;
|
||||
|
||||
pos = pos2 + 1;
|
||||
|
||||
if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
|
||||
return -1;
|
||||
|
||||
return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
|
||||
pmkid, expiration, akmp);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
|
||||
#ifdef CONFIG_MESH
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len)
|
||||
{
|
||||
return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
|
||||
{
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
char *pos;
|
||||
int expiration;
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <BSSID> <PMKID> <PMK> <expiration in seconds>
|
||||
*/
|
||||
|
||||
if (hwaddr_aton(cmd, spa))
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (sscanf(pos, "%d", &expiration) != 1)
|
||||
return NULL;
|
||||
|
||||
return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
@ -32,5 +32,9 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
|
||||
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
|
||||
size_t len);
|
||||
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
|
||||
int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd);
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len);
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* DFS - Dynamic Frequency Selection
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -747,6 +747,23 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
|
||||
{
|
||||
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
|
||||
|
||||
/* Get the start (first) channel for current configuration */
|
||||
start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
|
||||
if (start_chan_idx < 0)
|
||||
return 0;
|
||||
|
||||
/* Get the number of used channels, depending on width */
|
||||
n_chans = dfs_get_used_n_chans(iface, &n_chans1);
|
||||
|
||||
/* Check if all channels are DFS available */
|
||||
return dfs_check_chans_available(iface, start_chan_idx, n_chans);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
@ -767,8 +784,21 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset,
|
||||
chan_width, cf1, cf2,
|
||||
HOSTAPD_CHAN_DFS_AVAILABLE);
|
||||
iface->cac_started = 0;
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
/*
|
||||
* Just mark the channel available when CAC completion
|
||||
* event is received in enabled state. CAC result could
|
||||
* have been propagated from another radio having the
|
||||
* same regulatory configuration. When CAC completion is
|
||||
* received during non-HAPD_IFACE_ENABLED state, make
|
||||
* sure the configured channel is available because this
|
||||
* CAC completion event could have been propagated from
|
||||
* another radio.
|
||||
*/
|
||||
if (iface->state != HAPD_IFACE_ENABLED &&
|
||||
hostapd_config_dfs_chan_available(iface)) {
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
iface->cac_started = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,6 +806,25 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
{
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
|
||||
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
|
||||
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
|
||||
|
||||
/* Proceed only if DFS is not offloaded to the driver */
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
|
||||
return 0;
|
||||
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
@ -840,6 +889,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
if (iface->cac_started)
|
||||
return hostapd_dfs_start_channel_switch_cac(iface);
|
||||
|
||||
/*
|
||||
* Allow selection of DFS channel in ETSI to comply with
|
||||
* uniform spreading.
|
||||
*/
|
||||
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
|
||||
skip_radar = 0;
|
||||
|
||||
/* Perform channel switch/CSA */
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&vht_oper_centr_freq_seg0_idx,
|
||||
@ -1055,7 +1111,8 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ieee80211_is_dfs(iface->freq)) {
|
||||
if (ieee80211_is_dfs(iface->freq, iface->hw_features,
|
||||
iface->num_hw_features)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
|
||||
__func__, iface->freq);
|
||||
return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* DFS - Dynamic Frequency Selection
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -14,6 +14,9 @@ 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_pre_cac_expired(struct hostapd_iface *iface, 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,
|
||||
|
@ -7,10 +7,9 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/dhcp.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
@ -18,29 +17,6 @@
|
||||
#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)
|
||||
{
|
||||
@ -74,24 +50,26 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
if (tot_len > (unsigned int) (len - ETH_HLEN))
|
||||
return;
|
||||
|
||||
if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
|
||||
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
|
||||
return;
|
||||
|
||||
/* Parse DHCP options */
|
||||
end = (const u8 *) b + tot_len;
|
||||
pos = &b->exten[4];
|
||||
while (pos < end && *pos != 0xff) {
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
const u8 *opt = pos++;
|
||||
|
||||
if (*opt == 0) /* padding */
|
||||
if (*opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
|
||||
if (pos >= end || 1 + *pos > end - pos)
|
||||
break;
|
||||
pos += *pos + 1;
|
||||
if (pos >= end)
|
||||
break;
|
||||
|
||||
switch (*opt) {
|
||||
case 1: /* subnet mask */
|
||||
case DHCP_OPT_SUBNET_MASK:
|
||||
if (opt[1] == 4)
|
||||
subnet_mask = WPA_GET_BE32(&opt[2]);
|
||||
if (subnet_mask == 0)
|
||||
@ -101,7 +79,7 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
prefixlen--;
|
||||
}
|
||||
break;
|
||||
case 53: /* message type */
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (opt[1])
|
||||
msgtype = opt[2];
|
||||
break;
|
||||
@ -176,4 +154,5 @@ int dhcp_snoop_init(struct hostapd_data *hapd)
|
||||
void dhcp_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
l2_packet_deinit(hapd->sock_dhcp);
|
||||
hapd->sock_dhcp = NULL;
|
||||
}
|
||||
|
2096
contrib/wpa/src/ap/dpp_hostapd.c
Normal file
2096
contrib/wpa/src/ap/dpp_hostapd.c
Normal file
File diff suppressed because it is too large
Load Diff
43
contrib/wpa/src/ap/dpp_hostapd.h
Normal file
43
contrib/wpa/src/ap/dpp_hostapd.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* hostapd / DPP integration
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPP_HOSTAPD_H
|
||||
#define DPP_HOSTAPD_H
|
||||
|
||||
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id);
|
||||
const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
|
||||
unsigned int id);
|
||||
int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
|
||||
char *reply, int reply_size);
|
||||
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *buf, size_t len, unsigned int freq);
|
||||
void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok);
|
||||
struct wpabuf *
|
||||
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 *query, size_t query_len);
|
||||
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
|
||||
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
|
||||
int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
|
||||
void hostapd_dpp_stop(struct hostapd_data *hapd);
|
||||
int hostapd_dpp_init(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
|
||||
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
|
||||
|
||||
#endif /* DPP_HOSTAPD_H */
|
@ -31,10 +31,74 @@
|
||||
#include "wps_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_mlme.h"
|
||||
#include "hw_features.h"
|
||||
#include "dfs.h"
|
||||
#include "beacon.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "fils_hlp.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
u16 reply_res = WLAN_STATUS_SUCCESS;
|
||||
struct ieee802_11_elems elems;
|
||||
u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
|
||||
int new_assoc;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
|
||||
__func__, MAC2STR(sta->addr));
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
if (!sta->fils_pending_assoc_req)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(sta->fils_pending_assoc_req,
|
||||
sta->fils_pending_assoc_req_len, &elems, 0);
|
||||
if (!elems.fils_session) {
|
||||
wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
|
||||
elems.fils_session,
|
||||
sta->fils_hlp_resp);
|
||||
|
||||
reply_res = hostapd_sta_assoc(hapd, sta->addr,
|
||||
sta->fils_pending_assoc_is_reassoc,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
buf, p - buf);
|
||||
ap_sta_set_authorized(hapd, sta, 1);
|
||||
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);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
sta->fils_pending_assoc_req = NULL;
|
||||
sta->fils_pending_assoc_req_len = 0;
|
||||
wpabuf_free(sta->fils_hlp_resp);
|
||||
sta->fils_hlp_resp = NULL;
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
fils_hlp_deinit(hapd);
|
||||
|
||||
/*
|
||||
* Remove the station in case transmission of a success response fails
|
||||
* (the STA was added associated to the driver) or if the station was
|
||||
* previously added unassociated.
|
||||
*/
|
||||
if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->added_unassoc = 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -45,10 +109,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||
u8 *p = buf;
|
||||
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
|
||||
u16 reason = WLAN_REASON_UNSPECIFIED;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
const u8 *p2p_dev_addr = NULL;
|
||||
@ -171,6 +235,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
elems.hs20_len - 4);
|
||||
} else
|
||||
sta->hs20_ie = NULL;
|
||||
|
||||
wpabuf_free(sta->roaming_consortium);
|
||||
if (elems.roaming_cons_sel)
|
||||
sta->roaming_consortium = wpabuf_alloc_copy(
|
||||
elems.roaming_cons_sel + 4,
|
||||
elems.roaming_cons_sel_len - 4);
|
||||
else
|
||||
sta->roaming_consortium = NULL;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
@ -198,7 +270,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
|
||||
return -1;
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
|
||||
@ -231,7 +305,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
ie, ielen,
|
||||
elems.mdie, elems.mdie_len);
|
||||
elems.mdie, elems.mdie_len,
|
||||
elems.owe_dh, elems.owe_dh_len);
|
||||
if (res != WPA_IE_OK) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA/RSN information element rejected? (res %u)",
|
||||
@ -252,8 +327,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
|
||||
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else {
|
||||
@ -263,10 +338,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
(sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA
|
||||
@ -293,7 +372,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
sta->flags &= ~WLAN_STA_MFP;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
|
||||
req_ies_len);
|
||||
@ -307,7 +386,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
} else if (hapd->conf->wps_state) {
|
||||
#ifdef CONFIG_WPS
|
||||
struct wpabuf *wps;
|
||||
@ -375,19 +454,128 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
|
||||
sta->auth_alg, req_ies, req_ies_len);
|
||||
if (!p) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
|
||||
int delay_assoc = 0;
|
||||
|
||||
if (!req_ies)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
|
||||
req_ies_len,
|
||||
sta->fils_session)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Session validation failed");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
|
||||
req_ies_len);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Key Confirm validation failed");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Delaying Assoc Response (HLP)");
|
||||
delay_assoc = 1;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Going ahead with Assoc Response (no HLP)");
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
sta->fils_pending_assoc_req = NULL;
|
||||
sta->fils_pending_assoc_req_len = 0;
|
||||
wpabuf_free(sta->fils_hlp_resp);
|
||||
sta->fils_hlp_resp = NULL;
|
||||
sta->fils_drv_assoc_finish = 0;
|
||||
}
|
||||
|
||||
if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
|
||||
u8 *req_tmp;
|
||||
|
||||
req_tmp = os_malloc(req_ies_len);
|
||||
if (!req_tmp) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: buffer allocation failed for assoc req");
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(req_tmp, req_ies, req_ies_len);
|
||||
sta->fils_pending_assoc_req = req_tmp;
|
||||
sta->fils_pending_assoc_req_len = req_ies_len;
|
||||
sta->fils_pending_assoc_is_reassoc = reassoc;
|
||||
sta->fils_drv_assoc_finish = 1;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
eloop_register_timeout(
|
||||
0, hapd->conf->fils_hlp_wait_time * 1024,
|
||||
fils_hlp_timeout, hapd, sta);
|
||||
return 0;
|
||||
}
|
||||
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
|
||||
elems.fils_session,
|
||||
sta->fils_hlp_resp);
|
||||
wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
|
||||
buf, p - buf);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
|
||||
elems.owe_dh) {
|
||||
u8 *npos;
|
||||
|
||||
npos = owe_assoc_req_process(hapd, sta,
|
||||
elems.owe_dh, elems.owe_dh_len,
|
||||
p, sizeof(buf) - (p - buf),
|
||||
&reason);
|
||||
if (npos)
|
||||
p = npos;
|
||||
if (!npos &&
|
||||
reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
|
||||
status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
|
||||
p - buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!npos || reason != WLAN_STATUS_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
|
||||
if (sta->auth_alg == WLAN_AUTH_FT)
|
||||
if (sta->auth_alg == WLAN_AUTH_FT ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK)
|
||||
ap_sta_set_authorized(hapd, sta, 1);
|
||||
#else /* CONFIG_IEEE80211R */
|
||||
#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
|
||||
/* Keep compiler silent about unused variables */
|
||||
if (status) {
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
|
||||
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
@ -397,6 +585,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
|
||||
#ifdef CONFIG_FILS
|
||||
else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK)
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
|
||||
#endif /* CONFIG_FILS */
|
||||
else
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||
|
||||
@ -414,9 +608,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
|
||||
ap_free_sta(hapd, sta);
|
||||
return -1;
|
||||
@ -464,15 +658,81 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (!sta || !hapd->conf->disassoc_low_ack)
|
||||
if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"disconnected due to excessive missing ACKs");
|
||||
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
if (sta)
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
|
||||
enum smps_mode smps_mode,
|
||||
enum chan_width chan_width, u8 rx_nss)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
const char *txt;
|
||||
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
switch (smps_mode) {
|
||||
case SMPS_AUTOMATIC:
|
||||
txt = "automatic";
|
||||
break;
|
||||
case SMPS_OFF:
|
||||
txt = "off";
|
||||
break;
|
||||
case SMPS_DYNAMIC:
|
||||
txt = "dynamic";
|
||||
break;
|
||||
case SMPS_STATIC:
|
||||
txt = "static";
|
||||
break;
|
||||
default:
|
||||
txt = NULL;
|
||||
break;
|
||||
}
|
||||
if (txt) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
|
||||
MACSTR " %s", MAC2STR(addr), txt);
|
||||
}
|
||||
|
||||
switch (chan_width) {
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
txt = "20(no-HT)";
|
||||
break;
|
||||
case CHAN_WIDTH_20:
|
||||
txt = "20";
|
||||
break;
|
||||
case CHAN_WIDTH_40:
|
||||
txt = "40";
|
||||
break;
|
||||
case CHAN_WIDTH_80:
|
||||
txt = "80";
|
||||
break;
|
||||
case CHAN_WIDTH_80P80:
|
||||
txt = "80+80";
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
txt = "160";
|
||||
break;
|
||||
default:
|
||||
txt = NULL;
|
||||
break;
|
||||
}
|
||||
if (txt) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
|
||||
MACSTR " %s", MAC2STR(addr), txt);
|
||||
}
|
||||
|
||||
if (rx_nss != 0xff) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
|
||||
MACSTR " %d", MAC2STR(addr), rx_nss);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -485,9 +745,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
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);
|
||||
"driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
|
||||
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
|
||||
width, channel_width_to_string(width), cf1, cf2);
|
||||
|
||||
hapd->iface->freq = freq;
|
||||
|
||||
@ -532,14 +792,26 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
hapd->iconf->channel = channel;
|
||||
hapd->iconf->ieee80211n = ht;
|
||||
if (!ht)
|
||||
if (!ht) {
|
||||
hapd->iconf->ieee80211ac = 0;
|
||||
} else if (hapd->iconf->ch_switch_vht_config) {
|
||||
/* CHAN_SWITCH VHT config */
|
||||
if (hapd->iconf->ch_switch_vht_config &
|
||||
CH_SWITCH_VHT_ENABLED)
|
||||
hapd->iconf->ieee80211ac = 1;
|
||||
else if (hapd->iconf->ch_switch_vht_config &
|
||||
CH_SWITCH_VHT_DISABLED)
|
||||
hapd->iconf->ieee80211ac = 0;
|
||||
}
|
||||
hapd->iconf->ch_switch_vht_config = 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);
|
||||
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
|
||||
hapd->iface->num_hw_features);
|
||||
|
||||
if (hapd->csa_in_progress &&
|
||||
freq == hapd->cs_freq_params.freq) {
|
||||
@ -690,7 +962,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||
|
||||
#ifdef HOSTAPD
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
|
||||
const u8 *bssid,
|
||||
u16 auth_transaction, u16 status,
|
||||
@ -709,7 +981,33 @@ static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
|
||||
|
||||
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 resp,
|
||||
struct wpabuf *data, int pub)
|
||||
{
|
||||
if (resp == WLAN_STATUS_SUCCESS) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
|
||||
sta->flags |= WLAN_STA_AUTH;
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
|
||||
sta->auth_alg = WLAN_AUTH_FILS_SK;
|
||||
mlme_authenticate_indication(hapd, sta);
|
||||
} else {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"authentication failed (FILS)");
|
||||
}
|
||||
|
||||
hostapd_sta_auth(hapd, sta->addr, 2, resp,
|
||||
data ? wpabuf_head(data) : NULL,
|
||||
data ? wpabuf_len(data) : 0);
|
||||
wpabuf_free(data);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
@ -730,7 +1028,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
}
|
||||
sta->flags &= ~WLAN_STA_PREAUTH;
|
||||
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
if (sta->wpa_sm == NULL)
|
||||
@ -748,7 +1046,19 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
hostapd_notify_auth_ft_finish, hapd);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
|
||||
sta->auth_alg = WLAN_AUTH_FILS_SK;
|
||||
handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
|
||||
rx_auth->auth_type, rx_auth->auth_transaction,
|
||||
rx_auth->status_code,
|
||||
hostapd_notify_auth_fils_finish);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
fail:
|
||||
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
|
||||
status, resp_ies, resp_ies_len);
|
||||
@ -762,32 +1072,36 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
struct sta_info *sta;
|
||||
size_t plen __maybe_unused;
|
||||
u16 fc;
|
||||
u8 *action __maybe_unused;
|
||||
|
||||
if (drv_mgmt->frame_len < 24 + 1)
|
||||
if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
|
||||
return;
|
||||
|
||||
plen = drv_mgmt->frame_len - 24 - 1;
|
||||
plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 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",
|
||||
mgmt->u.action.category, (int) plen);
|
||||
action = (u8 *) &mgmt->u.action.u;
|
||||
wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
|
||||
" da " MACSTR " plen %d",
|
||||
mgmt->u.action.category, *action,
|
||||
MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
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 */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
|
||||
ieee802_11_sa_query_action(
|
||||
@ -796,18 +1110,34 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
mgmt->u.action.u.sa_query_resp.trans_id);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
|
||||
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
|
||||
}
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
#ifdef CONFIG_FST
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
|
||||
fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
#ifdef CONFIG_DPP
|
||||
if (plen >= 1 + 4 &&
|
||||
mgmt->u.action.u.vs_public_action.action ==
|
||||
WLAN_PA_VENDOR_SPECIFIC &&
|
||||
WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
|
||||
OUI_WFA &&
|
||||
mgmt->u.action.u.vs_public_action.variable[0] ==
|
||||
DPP_OUI_TYPE) {
|
||||
const u8 *pos, *end;
|
||||
|
||||
pos = mgmt->u.action.u.vs_public_action.oui;
|
||||
end = drv_mgmt->frame + drv_mgmt->frame_len;
|
||||
hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
|
||||
drv_mgmt->freq);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
}
|
||||
|
||||
|
||||
@ -891,6 +1221,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
}
|
||||
|
||||
os_memset(&fi, 0, sizeof(fi));
|
||||
fi.freq = rx_mgmt->freq;
|
||||
fi.datarate = rx_mgmt->datarate;
|
||||
fi.ssi_signal = rx_mgmt->ssi_signal;
|
||||
|
||||
@ -1122,6 +1453,16 @@ static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
|
||||
struct dfs_event *radar)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
|
||||
hostapd_dfs_pre_cac_expired(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)
|
||||
{
|
||||
@ -1164,6 +1505,28 @@ static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
|
||||
int istatus,
|
||||
const char *ifname,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (sta) {
|
||||
os_free(sta->ifname_wds);
|
||||
if (istatus == INTERFACE_ADDED)
|
||||
sta->ifname_wds = os_strdup(ifname);
|
||||
else
|
||||
sta->ifname_wds = NULL;
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
|
||||
istatus == INTERFACE_ADDED ?
|
||||
WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
|
||||
ifname, MAC2STR(addr));
|
||||
}
|
||||
|
||||
|
||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
@ -1314,6 +1677,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
break;
|
||||
hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
|
||||
break;
|
||||
case EVENT_DFS_PRE_CAC_EXPIRED:
|
||||
if (!data)
|
||||
break;
|
||||
hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
|
||||
break;
|
||||
case EVENT_DFS_CAC_FINISHED:
|
||||
if (!data)
|
||||
break;
|
||||
@ -1351,7 +1719,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
* Try to re-enable interface if the driver stopped it
|
||||
* when the interface got disabled.
|
||||
*/
|
||||
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
|
||||
if (hapd->wpa_auth)
|
||||
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
|
||||
else
|
||||
hostapd_reconfig_encryption(hapd);
|
||||
hapd->reenable_beacon = 1;
|
||||
ieee802_11_set_beacon(hapd);
|
||||
}
|
||||
@ -1367,6 +1738,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
&data->acs_selected_channels);
|
||||
break;
|
||||
#endif /* CONFIG_ACS */
|
||||
case EVENT_STATION_OPMODE_CHANGED:
|
||||
hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
|
||||
data->sta_opmode.smps_mode,
|
||||
data->sta_opmode.chan_width,
|
||||
data->sta_opmode.rx_nss);
|
||||
break;
|
||||
case EVENT_WDS_STA_INTERFACE_STATUS:
|
||||
hostapd_event_wds_sta_interface_status(
|
||||
hapd, data->wds_sta_interface.istatus,
|
||||
data->wds_sta_interface.ifname,
|
||||
data->wds_sta_interface.sta_addr);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||
break;
|
||||
|
@ -91,6 +91,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
|
||||
set_user_methods(user, argv[i]);
|
||||
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
|
||||
user->remediation = strlen(argv[i]) > 0;
|
||||
} else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
|
||||
user->t_c_timestamp = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
191
contrib/wpa/src/ap/eth_p_oui.c
Normal file
191
contrib/wpa/src/ap/eth_p_oui.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* hostapd / IEEE 802 OUI Extended EtherType 88-B7
|
||||
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "hostapd.h"
|
||||
#include "eth_p_oui.h"
|
||||
|
||||
/*
|
||||
* See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
|
||||
* EtherType 88-B7. This file implements this with OUI 00:13:74 and
|
||||
* vendor-specific subtype 0x0001.
|
||||
*/
|
||||
static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
|
||||
|
||||
struct eth_p_oui_iface {
|
||||
struct dl_list list;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct l2_packet_data *l2;
|
||||
struct dl_list receiver;
|
||||
};
|
||||
|
||||
struct eth_p_oui_ctx {
|
||||
struct dl_list list;
|
||||
struct eth_p_oui_iface *iface;
|
||||
/* all data needed to deliver and unregister */
|
||||
u8 oui_suffix; /* last byte of OUI */
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len);
|
||||
void *rx_callback_ctx;
|
||||
};
|
||||
|
||||
|
||||
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
|
||||
ctx->oui_suffix, buf, len);
|
||||
}
|
||||
|
||||
|
||||
static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
struct eth_p_oui_iface *iface = ctx;
|
||||
struct eth_p_oui_ctx *receiver;
|
||||
const struct l2_ethhdr *ethhdr;
|
||||
|
||||
if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
|
||||
/* too short packet */
|
||||
return;
|
||||
}
|
||||
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
/* trim eth_hdr from buf and len */
|
||||
buf += sizeof(*ethhdr);
|
||||
len -= sizeof(*ethhdr);
|
||||
|
||||
/* verify OUI and vendor-specific subtype match */
|
||||
if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
|
||||
return;
|
||||
buf += sizeof(global_oui);
|
||||
len -= sizeof(global_oui);
|
||||
|
||||
dl_list_for_each(receiver, &iface->receiver,
|
||||
struct eth_p_oui_ctx, list) {
|
||||
if (buf[0] != receiver->oui_suffix)
|
||||
continue;
|
||||
|
||||
eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
|
||||
buf + 1, len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct eth_p_oui_ctx *
|
||||
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len),
|
||||
void *rx_callback_ctx)
|
||||
{
|
||||
struct eth_p_oui_iface *iface;
|
||||
struct eth_p_oui_ctx *receiver;
|
||||
int found = 0;
|
||||
struct hapd_interfaces *interfaces;
|
||||
|
||||
receiver = os_zalloc(sizeof(*receiver));
|
||||
if (!receiver)
|
||||
goto err;
|
||||
|
||||
receiver->oui_suffix = oui_suffix;
|
||||
receiver->rx_callback = rx_callback;
|
||||
receiver->rx_callback_ctx = rx_callback_ctx;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
|
||||
dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
|
||||
list) {
|
||||
if (os_strcmp(iface->ifname, ifname) != 0)
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
iface = os_zalloc(sizeof(*iface));
|
||||
if (!iface)
|
||||
goto err;
|
||||
|
||||
os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
|
||||
iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
|
||||
iface, 1);
|
||||
if (!iface->l2) {
|
||||
os_free(iface);
|
||||
goto err;
|
||||
}
|
||||
dl_list_init(&iface->receiver);
|
||||
|
||||
dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
|
||||
}
|
||||
|
||||
dl_list_add_tail(&iface->receiver, &receiver->list);
|
||||
receiver->iface = iface;
|
||||
|
||||
return receiver;
|
||||
err:
|
||||
os_free(receiver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
|
||||
{
|
||||
struct eth_p_oui_iface *iface;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
iface = ctx->iface;
|
||||
|
||||
dl_list_del(&ctx->list);
|
||||
os_free(ctx);
|
||||
|
||||
if (dl_list_empty(&iface->receiver)) {
|
||||
dl_list_del(&iface->list);
|
||||
l2_packet_deinit(iface->l2);
|
||||
os_free(iface);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
struct eth_p_oui_iface *iface = ctx->iface;
|
||||
u8 *packet, *p;
|
||||
size_t packet_len;
|
||||
int ret;
|
||||
struct l2_ethhdr *ethhdr;
|
||||
|
||||
packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
|
||||
packet = os_zalloc(packet_len);
|
||||
if (!packet)
|
||||
return -1;
|
||||
p = packet;
|
||||
|
||||
ethhdr = (struct l2_ethhdr *) packet;
|
||||
os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
|
||||
os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
|
||||
ethhdr->h_proto = host_to_be16(ETH_P_OUI);
|
||||
p += sizeof(*ethhdr);
|
||||
|
||||
os_memcpy(p, global_oui, sizeof(global_oui));
|
||||
p[sizeof(global_oui)] = ctx->oui_suffix;
|
||||
p += sizeof(global_oui) + 1;
|
||||
|
||||
os_memcpy(p, buf, len);
|
||||
|
||||
ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
|
||||
os_free(packet);
|
||||
return ret;
|
||||
}
|
28
contrib/wpa/src/ap/eth_p_oui.h
Normal file
28
contrib/wpa/src/ap/eth_p_oui.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* hostapd / IEEE 802 OUI Extended Ethertype
|
||||
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef ETH_P_OUI_H
|
||||
#define ETH_P_OUI_H
|
||||
|
||||
struct eth_p_oui_ctx;
|
||||
struct hostapd_data;
|
||||
|
||||
/* rx_callback only gets payload after OUI passed as buf */
|
||||
struct eth_p_oui_ctx *
|
||||
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len),
|
||||
void *rx_callback_ctx);
|
||||
void eth_p_oui_unregister(struct eth_p_oui_ctx *eth_p_oui);
|
||||
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||
|
||||
#endif /* ETH_P_OUI_H */
|
641
contrib/wpa/src/ap/fils_hlp.c
Normal file
641
contrib/wpa/src/ap/fils_hlp.c
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* FILS HLP request processing
|
||||
* Copyright (c) 2017, 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 "common/dhcp.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "fils_hlp.h"
|
||||
|
||||
|
||||
static be16 ip_checksum(const void *buf, size_t len)
|
||||
{
|
||||
u32 sum = 0;
|
||||
const u16 *pos;
|
||||
|
||||
for (pos = buf; len >= 2; len -= 2)
|
||||
sum += ntohs(*pos++);
|
||||
if (len)
|
||||
sum += ntohs(*pos << 8);
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += sum >> 16;
|
||||
return htons(~sum);
|
||||
}
|
||||
|
||||
|
||||
static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
|
||||
{
|
||||
u8 *pos, *end;
|
||||
struct dhcp_data *dhcp;
|
||||
struct sockaddr_in addr;
|
||||
ssize_t res;
|
||||
const u8 *server_id = NULL;
|
||||
|
||||
if (!sta->hlp_dhcp_discover) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No pending HLP DHCPDISCOVER available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert to DHCPREQUEST, remove rapid commit option, replace requested
|
||||
* IP address option with yiaddr. */
|
||||
pos = wpabuf_mhead(sta->hlp_dhcp_discover);
|
||||
end = pos + wpabuf_len(sta->hlp_dhcp_discover);
|
||||
dhcp = (struct dhcp_data *) pos;
|
||||
pos = (u8 *) (dhcp + 1);
|
||||
pos += 4; /* skip magic */
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
*pos = DHCPREQUEST;
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
case DHCP_OPT_REQUESTED_IP_ADDRESS:
|
||||
case DHCP_OPT_SERVER_ID:
|
||||
/* Remove option */
|
||||
pos -= 2;
|
||||
os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
|
||||
end -= 2 + olen;
|
||||
olen = 0;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
if (pos >= end || *pos != DHCP_OPT_END) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
|
||||
return -1;
|
||||
}
|
||||
sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
|
||||
|
||||
/* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
|
||||
pos = (u8 *) (dhcpoffer + 1);
|
||||
end = dhcpofferend;
|
||||
pos += 4; /* skip magic */
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_SERVER_ID:
|
||||
server_id = pos - 2;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
|
||||
if (wpabuf_resize(&sta->hlp_dhcp_discover,
|
||||
6 + 1 + (server_id ? 2 + server_id[1] : 0)))
|
||||
return -1;
|
||||
if (server_id)
|
||||
wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
|
||||
2 + server_id[1]);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
|
||||
wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_server_port);
|
||||
res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
|
||||
wpabuf_len(sta->hlp_dhcp_discover), 0,
|
||||
(const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Acting as DHCP rapid commit proxy for %s:%d",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
sta->fils_dhcp_rapid_commit_proxy = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = sock_ctx;
|
||||
struct sta_info *sta;
|
||||
u8 buf[1500], *pos, *end, *end_opt = NULL;
|
||||
struct dhcp_data *dhcp;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
ssize_t res;
|
||||
u8 msgtype = 0;
|
||||
int rapid_commit = 0;
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
struct wpabuf *resp;
|
||||
const u8 *rpos;
|
||||
size_t left, len;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
res = recvfrom(sd, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *) &addr, &addr_len);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
|
||||
if ((size_t) res < sizeof(*dhcp))
|
||||
return;
|
||||
dhcp = (struct dhcp_data *) buf;
|
||||
if (dhcp->op != 2)
|
||||
return; /* Not a BOOTREPLY */
|
||||
if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - DHCP response to unknown relay address 0x%x",
|
||||
dhcp->relay_ip);
|
||||
return;
|
||||
}
|
||||
dhcp->relay_ip = 0;
|
||||
pos = (u8 *) (dhcp + 1);
|
||||
end = &buf[res];
|
||||
|
||||
if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
|
||||
return;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
|
||||
pos, end - pos);
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
msgtype = pos[0];
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
rapid_commit = 1;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
if (pos < end && *pos == DHCP_OPT_END)
|
||||
end_opt = pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
|
||||
MACSTR ")",
|
||||
msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
|
||||
|
||||
sta = ap_get_sta(hapd, dhcp->hw_addr);
|
||||
if (!sta || !sta->fils_pending_assoc_req) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No pending HLP DHCP exchange with hw_addr "
|
||||
MACSTR, MAC2STR(dhcp->hw_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
|
||||
!rapid_commit) {
|
||||
/* Use hostapd to take care of 4-message exchange and convert
|
||||
* the final DHCPACK to rapid commit version. */
|
||||
if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
|
||||
return;
|
||||
/* failed, so send the server response as-is */
|
||||
} else if (msgtype != DHCPACK) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
|
||||
}
|
||||
|
||||
pos = buf;
|
||||
resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
|
||||
sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
|
||||
if (!resp)
|
||||
return;
|
||||
wpabuf_put_data(resp, sta->addr, ETH_ALEN);
|
||||
wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
|
||||
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
|
||||
wpabuf_put_be16(resp, ETH_P_IP);
|
||||
iph = wpabuf_put(resp, sizeof(*iph));
|
||||
iph->version = 4;
|
||||
iph->ihl = sizeof(*iph) / 4;
|
||||
iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
|
||||
iph->ttl = 1;
|
||||
iph->protocol = 17; /* UDP */
|
||||
iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
iph->daddr = dhcp->client_ip;
|
||||
iph->check = ip_checksum(iph, sizeof(*iph));
|
||||
udph = wpabuf_put(resp, sizeof(*udph));
|
||||
udph->uh_sport = htons(DHCP_SERVER_PORT);
|
||||
udph->uh_dport = htons(DHCP_CLIENT_PORT);
|
||||
udph->uh_ulen = htons(sizeof(*udph) + (end - pos));
|
||||
udph->uh_sum = htons(0x0000); /* TODO: calculate checksum */
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
|
||||
!rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
|
||||
/* Add rapid commit option */
|
||||
wpabuf_put_data(resp, pos, end_opt - pos);
|
||||
wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
|
||||
wpabuf_put_u8(resp, 0);
|
||||
wpabuf_put_data(resp, end_opt, end - end_opt);
|
||||
} else {
|
||||
wpabuf_put_data(resp, pos, end - pos);
|
||||
}
|
||||
if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
|
||||
2 * wpabuf_len(resp) / 255 + 100)) {
|
||||
wpabuf_free(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
rpos = wpabuf_head(resp);
|
||||
left = wpabuf_len(resp);
|
||||
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
|
||||
if (left <= 254)
|
||||
len = 1 + left;
|
||||
else
|
||||
len = 255;
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
|
||||
/* Element ID Extension */
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
|
||||
/* Destination MAC Address, Source MAC Address, HLP Packet.
|
||||
* HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
|
||||
* when LPD is used). */
|
||||
wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
|
||||
rpos += len - 1;
|
||||
left -= len - 1;
|
||||
while (left) {
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
|
||||
len = left > 255 ? 255 : left;
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, len);
|
||||
wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
|
||||
rpos += len;
|
||||
left -= len;
|
||||
}
|
||||
wpabuf_free(resp);
|
||||
|
||||
if (sta->fils_drv_assoc_finish)
|
||||
hostapd_notify_assoc_fils_finish(hapd, sta);
|
||||
else
|
||||
fils_hlp_finish_assoc(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *msg, size_t len)
|
||||
{
|
||||
const struct dhcp_data *dhcp;
|
||||
struct wpabuf *dhcp_buf;
|
||||
struct dhcp_data *dhcp_msg;
|
||||
u8 msgtype = 0;
|
||||
int rapid_commit = 0;
|
||||
const u8 *pos = msg, *end;
|
||||
struct sockaddr_in addr;
|
||||
ssize_t res;
|
||||
|
||||
if (len < sizeof(*dhcp))
|
||||
return 0;
|
||||
dhcp = (const struct dhcp_data *) pos;
|
||||
end = pos + len;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
|
||||
dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
|
||||
ntohl(dhcp->xid));
|
||||
pos += sizeof(*dhcp);
|
||||
if (dhcp->op != 1)
|
||||
return 0; /* Not a BOOTREQUEST */
|
||||
|
||||
if (end - pos < 4)
|
||||
return 0;
|
||||
if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
|
||||
return 0;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
msgtype = pos[0];
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
rapid_commit = 1;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
|
||||
if (msgtype != DHCPDISCOVER)
|
||||
return 0;
|
||||
|
||||
if (hapd->conf->dhcp_server.af != AF_INET ||
|
||||
hapd->conf->dhcp_server.u.v4.s_addr == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - no DHCPv4 server configured - drop request");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->conf->own_ip_addr.af != AF_INET ||
|
||||
hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - no IPv4 own_ip_addr configured - drop request");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->dhcp_sock < 0) {
|
||||
int s;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"FILS: Failed to open DHCP socket: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->conf->dhcp_relay_port) {
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr =
|
||||
hapd->conf->own_ip_addr.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_relay_port);
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"FILS: Failed to bind DHCP socket: %s",
|
||||
strerror(errno));
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (eloop_register_sock(s, EVENT_TYPE_READ,
|
||||
fils_dhcp_handler, NULL, hapd)) {
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hapd->dhcp_sock = s;
|
||||
}
|
||||
|
||||
dhcp_buf = wpabuf_alloc(len);
|
||||
if (!dhcp_buf)
|
||||
return 0;
|
||||
dhcp_msg = wpabuf_put(dhcp_buf, len);
|
||||
os_memcpy(dhcp_msg, msg, len);
|
||||
dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_server_port);
|
||||
res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
|
||||
(const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
|
||||
strerror(errno));
|
||||
wpabuf_free(dhcp_buf);
|
||||
/* Close the socket to try to recover from error */
|
||||
eloop_unregister_read_sock(hapd->dhcp_sock);
|
||||
close(hapd->dhcp_sock);
|
||||
hapd->dhcp_sock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
|
||||
rapid_commit);
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
|
||||
/* Store a copy of the DHCPDISCOVER for rapid commit proxying
|
||||
* purposes if the server does not support the rapid commit
|
||||
* option. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Store DHCPDISCOVER for rapid commit proxy");
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = dhcp_buf;
|
||||
} else {
|
||||
wpabuf_free(dhcp_buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_udp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, const u8 *dst,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
const struct udphdr *udph;
|
||||
u16 sport, dport, ulen;
|
||||
|
||||
if (len < sizeof(*iph) + sizeof(*udph))
|
||||
return 0;
|
||||
iph = (const struct iphdr *) pos;
|
||||
udph = (const struct udphdr *) (iph + 1);
|
||||
sport = ntohs(udph->uh_sport);
|
||||
dport = ntohs(udph->uh_dport);
|
||||
ulen = ntohs(udph->uh_ulen);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
|
||||
sport, dport, ulen, ntohs(udph->uh_sum));
|
||||
/* TODO: Check UDP checksum */
|
||||
if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
|
||||
return 0;
|
||||
|
||||
if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
|
||||
return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
|
||||
ulen - sizeof(*udph));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_ip(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, const u8 *dst,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
u16 tot_len;
|
||||
|
||||
if (len < sizeof(*iph))
|
||||
return 0;
|
||||
iph = (const struct iphdr *) pos;
|
||||
if (ip_checksum(iph, sizeof(*iph)) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
|
||||
return 0;
|
||||
}
|
||||
tot_len = ntohs(iph->tot_len);
|
||||
if (tot_len > len)
|
||||
return 0;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
|
||||
iph->saddr, iph->daddr, iph->protocol);
|
||||
switch (iph->protocol) {
|
||||
case 17:
|
||||
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_req(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *pkt, *end;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
|
||||
" src=" MACSTR " len=%u)",
|
||||
MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
|
||||
(unsigned int) len);
|
||||
if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Ignore HLP request with unexpected source address"
|
||||
MACSTR, MAC2STR(pos + ETH_ALEN));
|
||||
return 0;
|
||||
}
|
||||
|
||||
end = pos + len;
|
||||
pkt = pos + 2 * ETH_ALEN;
|
||||
if (end - pkt >= 6 &&
|
||||
os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
|
||||
pkt += 6; /* Remove SNAP/LLC header */
|
||||
wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
|
||||
|
||||
if (end - pkt < 2)
|
||||
return 0;
|
||||
|
||||
switch (WPA_GET_BE16(pkt)) {
|
||||
case ETH_P_IP:
|
||||
return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
|
||||
end - pkt - 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *pos, int left)
|
||||
{
|
||||
const u8 *end = pos + left;
|
||||
u8 *tmp, *tmp_pos;
|
||||
int ret = 0;
|
||||
|
||||
/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
sta->fils_dhcp_rapid_commit_proxy = 0;
|
||||
|
||||
/* Check if there are any FILS HLP Container elements */
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
return 0;
|
||||
if (pos[0] == WLAN_EID_EXTENSION &&
|
||||
pos[1] >= 1 + 2 * ETH_ALEN &&
|
||||
pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
|
||||
break;
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
if (end - pos < 2)
|
||||
return 0; /* No FILS HLP Container elements */
|
||||
|
||||
tmp = os_malloc(end - pos);
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos ||
|
||||
pos[0] != WLAN_EID_EXTENSION ||
|
||||
pos[1] < 1 + 2 * ETH_ALEN ||
|
||||
pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
|
||||
break;
|
||||
tmp_pos = tmp;
|
||||
os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
|
||||
tmp_pos += pos[1] - 1;
|
||||
pos += 2 + pos[1];
|
||||
|
||||
/* Add possible fragments */
|
||||
while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
|
||||
2 + pos[1] <= end - pos) {
|
||||
os_memcpy(tmp_pos, pos + 2, pos[1]);
|
||||
tmp_pos += pos[1];
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
os_free(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void fils_hlp_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->dhcp_sock >= 0) {
|
||||
eloop_unregister_read_sock(hapd->dhcp_sock);
|
||||
close(hapd->dhcp_sock);
|
||||
hapd->dhcp_sock = -1;
|
||||
}
|
||||
}
|
27
contrib/wpa/src/ap/fils_hlp.h
Normal file
27
contrib/wpa/src/ap/fils_hlp.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* FILS HLP request processing
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILS_HLP_H
|
||||
#define FILS_HLP_H
|
||||
|
||||
int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *pos, int left);
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
|
||||
void fils_hlp_deinit(struct hostapd_data *hapd);
|
||||
|
||||
#else /* CONFIG_FILS */
|
||||
|
||||
static inline void fils_hlp_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#endif /* FILS_HLP_H */
|
714
contrib/wpa/src/ap/gas_query_ap.c
Normal file
714
contrib/wpa/src/ap/gas_query_ap.c
Normal file
@ -0,0 +1,714 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) query (hostapd)
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/list.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/gas.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "gas_query_ap.h"
|
||||
|
||||
|
||||
/** GAS query timeout in seconds */
|
||||
#define GAS_QUERY_TIMEOUT_PERIOD 2
|
||||
|
||||
/* GAS query wait-time / duration in ms */
|
||||
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
|
||||
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
|
||||
|
||||
/**
|
||||
* struct gas_query_pending - Pending GAS query
|
||||
*/
|
||||
struct gas_query_pending {
|
||||
struct dl_list list;
|
||||
struct gas_query_ap *gas;
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 dialog_token;
|
||||
u8 next_frag_id;
|
||||
unsigned int wait_comeback:1;
|
||||
unsigned int offchannel_tx_started:1;
|
||||
unsigned int retry:1;
|
||||
int freq;
|
||||
u16 status_code;
|
||||
struct wpabuf *req;
|
||||
struct wpabuf *adv_proto;
|
||||
struct wpabuf *resp;
|
||||
struct os_reltime last_oper;
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code);
|
||||
void *ctx;
|
||||
u8 sa[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gas_query_ap - Internal GAS query data
|
||||
*/
|
||||
struct gas_query_ap {
|
||||
struct hostapd_data *hapd;
|
||||
void *msg_ctx;
|
||||
struct dl_list pending; /* struct gas_query_pending */
|
||||
struct gas_query_pending *current;
|
||||
};
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_tx_initial_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query);
|
||||
static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst);
|
||||
|
||||
|
||||
static int ms_from_time(struct os_reltime *last)
|
||||
{
|
||||
struct os_reltime now, res;
|
||||
|
||||
os_get_reltime(&now);
|
||||
os_reltime_sub(&now, last, &res);
|
||||
return res.sec * 1000 + res.usec / 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_init - Initialize GAS query component
|
||||
* @hapd: Pointer to hostapd data
|
||||
* Returns: Pointer to GAS query data or %NULL on failure
|
||||
*/
|
||||
struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
|
||||
void *msg_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas;
|
||||
|
||||
gas = os_zalloc(sizeof(*gas));
|
||||
if (!gas)
|
||||
return NULL;
|
||||
|
||||
gas->hapd = hapd;
|
||||
gas->msg_ctx = msg_ctx;
|
||||
dl_list_init(&gas->pending);
|
||||
|
||||
return gas;
|
||||
}
|
||||
|
||||
|
||||
static const char * gas_result_txt(enum gas_query_ap_result result)
|
||||
{
|
||||
switch (result) {
|
||||
case GAS_QUERY_AP_SUCCESS:
|
||||
return "SUCCESS";
|
||||
case GAS_QUERY_AP_FAILURE:
|
||||
return "FAILURE";
|
||||
case GAS_QUERY_AP_TIMEOUT:
|
||||
return "TIMEOUT";
|
||||
case GAS_QUERY_AP_PEER_ERROR:
|
||||
return "PEER_ERROR";
|
||||
case GAS_QUERY_AP_INTERNAL_ERROR:
|
||||
return "INTERNAL_ERROR";
|
||||
case GAS_QUERY_AP_DELETED_AT_DEINIT:
|
||||
return "DELETED_AT_DEINIT";
|
||||
}
|
||||
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_free(struct gas_query_pending *query, int del_list)
|
||||
{
|
||||
if (del_list)
|
||||
dl_list_del(&query->list);
|
||||
|
||||
wpabuf_free(query->req);
|
||||
wpabuf_free(query->adv_proto);
|
||||
wpabuf_free(query->resp);
|
||||
os_free(query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_done(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
enum gas_query_ap_result result)
|
||||
{
|
||||
wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
|
||||
" dialog_token=%u freq=%d status_code=%u result=%s",
|
||||
MAC2STR(query->addr), query->dialog_token, query->freq,
|
||||
query->status_code, gas_result_txt(result));
|
||||
if (gas->current == query)
|
||||
gas->current = NULL;
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
|
||||
dl_list_del(&query->list);
|
||||
query->cb(query->ctx, query->addr, query->dialog_token, result,
|
||||
query->adv_proto, query->resp, query->status_code);
|
||||
gas_query_free(query, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_deinit - Deinitialize GAS query component
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
*/
|
||||
void gas_query_ap_deinit(struct gas_query_ap *gas)
|
||||
{
|
||||
struct gas_query_pending *query, *next;
|
||||
|
||||
if (gas == NULL)
|
||||
return;
|
||||
|
||||
dl_list_for_each_safe(query, next, &gas->pending,
|
||||
struct gas_query_pending, list)
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_DELETED_AT_DEINIT);
|
||||
|
||||
os_free(gas);
|
||||
}
|
||||
|
||||
|
||||
static struct gas_query_pending *
|
||||
gas_query_get_pending(struct gas_query_ap *gas, const u8 *addr, u8 dialog_token)
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
|
||||
q->dialog_token == dialog_token)
|
||||
return q;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_append(struct gas_query_pending *query, const u8 *data,
|
||||
size_t len)
|
||||
{
|
||||
if (wpabuf_resize(&query->resp, len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
|
||||
return -1;
|
||||
}
|
||||
wpabuf_put_data(query->resp, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
int dur;
|
||||
|
||||
if (!gas || !gas->current) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: dst=" MACSTR
|
||||
" ok=%d - no query in progress", MAC2STR(dst), ok);
|
||||
return;
|
||||
}
|
||||
|
||||
query = gas->current;
|
||||
|
||||
dur = ms_from_time(&query->last_oper);
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status: dst=" MACSTR
|
||||
" ok=%d query=%p dialog_token=%u dur=%d ms",
|
||||
MAC2STR(dst), ok, query, query->dialog_token, dur);
|
||||
if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
|
||||
return;
|
||||
}
|
||||
os_get_reltime(&query->last_oper);
|
||||
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
if (!ok) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request");
|
||||
eloop_register_timeout(0, 250000, gas_query_timeout,
|
||||
gas, query);
|
||||
} else {
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
|
||||
gas_query_timeout, gas, query);
|
||||
}
|
||||
if (query->wait_comeback && !query->retry) {
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout,
|
||||
gas, query);
|
||||
eloop_register_timeout(
|
||||
0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
|
||||
gas_query_rx_comeback_timeout, gas, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int pmf_in_use(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
return sta && (sta->flags & WLAN_STA_MFP);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_tx(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
struct wpabuf *req, unsigned int wait_time)
|
||||
{
|
||||
int res, prot = pmf_in_use(gas->hapd, query->addr);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
|
||||
"freq=%d prot=%d using src addr " MACSTR,
|
||||
MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
|
||||
query->freq, prot, MAC2STR(query->sa));
|
||||
if (prot) {
|
||||
u8 *categ = wpabuf_mhead_u8(req);
|
||||
*categ = WLAN_ACTION_PROTECTED_DUAL;
|
||||
}
|
||||
os_get_reltime(&query->last_oper);
|
||||
res = hostapd_drv_send_action(gas->hapd, query->freq, wait_time,
|
||||
query->addr, wpabuf_head(req),
|
||||
wpabuf_len(req));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
unsigned int wait_time;
|
||||
|
||||
req = gas_build_comeback_req(query->dialog_token);
|
||||
if (req == NULL) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
wait_time = (query->retry || !query->offchannel_tx_started) ?
|
||||
GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
|
||||
|
||||
if (gas_query_tx(gas, query, req, wait_time) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
wpabuf_free(req);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
int dialog_token;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No response to comeback request received (retry=%u)",
|
||||
query->retry);
|
||||
if (gas->current != query || query->retry)
|
||||
return;
|
||||
dialog_token = gas_query_new_dialog_token(gas, query->addr);
|
||||
if (dialog_token < 0)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Retry GAS query due to comeback response timeout");
|
||||
query->retry = 1;
|
||||
query->dialog_token = dialog_token;
|
||||
*(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
|
||||
query->wait_comeback = 0;
|
||||
query->next_frag_id = 0;
|
||||
wpabuf_free(query->adv_proto);
|
||||
query->adv_proto = NULL;
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
gas_query_tx_initial_req(gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
|
||||
MAC2STR(query->addr));
|
||||
gas_query_tx_comeback_req(gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_req_delay(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
u16 comeback_delay)
|
||||
{
|
||||
unsigned int secs, usecs;
|
||||
|
||||
secs = (comeback_delay * 1024) / 1000000;
|
||||
usecs = comeback_delay * 1024 - secs * 1000000;
|
||||
wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
|
||||
" in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
|
||||
gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_initial(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
const u8 *adv_proto, const u8 *resp,
|
||||
size_t len, u16 comeback_delay)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
|
||||
MACSTR " (dialog_token=%u comeback_delay=%u)",
|
||||
MAC2STR(query->addr), query->dialog_token, comeback_delay);
|
||||
|
||||
query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
|
||||
if (query->adv_proto == NULL) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comeback_delay) {
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
query->wait_comeback = 1;
|
||||
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Query was completed without comeback mechanism */
|
||||
if (gas_query_append(query, resp, len) < 0) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_comeback(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
const u8 *adv_proto, const u8 *resp,
|
||||
size_t len, u8 frag_id, u8 more_frags,
|
||||
u16 comeback_delay)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
|
||||
MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
|
||||
"comeback_delay=%u)",
|
||||
MAC2STR(query->addr), query->dialog_token, frag_id,
|
||||
more_frags, comeback_delay);
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
|
||||
|
||||
if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
|
||||
os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
|
||||
wpabuf_len(query->adv_proto)) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
|
||||
"between initial and comeback response from "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comeback_delay) {
|
||||
if (frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
|
||||
"with non-zero frag_id and comeback_delay "
|
||||
"from " MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
if (frag_id != query->next_frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
|
||||
"from " MACSTR, MAC2STR(query->addr));
|
||||
if (frag_id + 1 == query->next_frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
|
||||
"retry of previous fragment");
|
||||
return;
|
||||
}
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
query->next_frag_id++;
|
||||
|
||||
if (gas_query_append(query, resp, len) < 0) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (more_frags) {
|
||||
gas_query_tx_comeback_req(gas, query);
|
||||
return;
|
||||
}
|
||||
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_rx - Indicate reception of a Public Action or Protected Dual
|
||||
* frame
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
* @sa: Source MAC address of the Action frame
|
||||
* @categ: Category of the Action frame
|
||||
* @data: Payload of the Action frame
|
||||
* @len: Length of @data
|
||||
* @freq: Frequency (in MHz) on which the frame was received
|
||||
* Returns: 0 if the Public Action frame was a GAS frame or -1 if not
|
||||
*/
|
||||
int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
|
||||
const u8 *data, size_t len, int freq)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
u8 action, dialog_token, frag_id = 0, more_frags = 0;
|
||||
u16 comeback_delay, resp_len;
|
||||
const u8 *pos, *adv_proto;
|
||||
int prot, pmf;
|
||||
unsigned int left;
|
||||
|
||||
if (!gas || len < 4)
|
||||
return -1;
|
||||
|
||||
pos = data;
|
||||
action = *pos++;
|
||||
dialog_token = *pos++;
|
||||
|
||||
if (action != WLAN_PA_GAS_INITIAL_RESP &&
|
||||
action != WLAN_PA_GAS_COMEBACK_RESP)
|
||||
return -1; /* Not a GAS response */
|
||||
|
||||
prot = categ == WLAN_ACTION_PROTECTED_DUAL;
|
||||
pmf = pmf_in_use(gas->hapd, sa);
|
||||
if (prot && !pmf) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
|
||||
return 0;
|
||||
}
|
||||
if (!prot && pmf) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
query = gas_query_get_pending(gas, sa, dialog_token);
|
||||
if (query == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
|
||||
" dialog token %u", MAC2STR(sa), dialog_token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR,
|
||||
ms_from_time(&query->last_oper), MAC2STR(sa));
|
||||
|
||||
if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
|
||||
MACSTR " dialog token %u when waiting for comeback "
|
||||
"response", MAC2STR(sa), dialog_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
|
||||
MACSTR " dialog token %u when waiting for initial "
|
||||
"response", MAC2STR(sa), dialog_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
query->status_code = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING &&
|
||||
action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response");
|
||||
} else if (query->status_code != WLAN_STATUS_SUCCESS) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
|
||||
"%u failed - status code %u",
|
||||
MAC2STR(sa), dialog_token, query->status_code);
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
if (pos + 1 > data + len)
|
||||
return 0;
|
||||
frag_id = *pos & 0x7f;
|
||||
more_frags = (*pos & 0x80) >> 7;
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* Comeback Delay */
|
||||
if (pos + 2 > data + len)
|
||||
return 0;
|
||||
comeback_delay = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
|
||||
"Protocol element in the response from " MACSTR,
|
||||
MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*pos != WLAN_EID_ADV_PROTO) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
|
||||
"Protocol element ID %u in response from " MACSTR,
|
||||
*pos, MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
adv_proto = pos;
|
||||
pos += 2 + pos[1];
|
||||
|
||||
/* Query Response Length */
|
||||
if (pos + 2 > data + len) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
|
||||
return 0;
|
||||
}
|
||||
resp_len = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
left = data + len - pos;
|
||||
if (resp_len > left) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
|
||||
"response from " MACSTR, MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (resp_len < left) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
|
||||
"after Query Response from " MACSTR,
|
||||
left - resp_len, MAC2STR(sa));
|
||||
}
|
||||
|
||||
if (action == WLAN_PA_GAS_COMEBACK_RESP)
|
||||
gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
|
||||
frag_id, more_frags, comeback_delay);
|
||||
else
|
||||
gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
|
||||
comeback_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
|
||||
" dialog token %u",
|
||||
MAC2STR(query->addr), query->dialog_token);
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_dialog_token_available(struct gas_query_ap *gas,
|
||||
const u8 *dst, u8 dialog_token)
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
|
||||
dialog_token == q->dialog_token)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_initial_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query)
|
||||
{
|
||||
if (gas_query_tx(gas, query, query->req,
|
||||
GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
gas->current = query;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
|
||||
query->dialog_token);
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
|
||||
gas_query_timeout, gas, query);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst)
|
||||
{
|
||||
static int next_start = 0;
|
||||
int dialog_token;
|
||||
|
||||
for (dialog_token = 0; dialog_token < 256; dialog_token++) {
|
||||
if (gas_query_dialog_token_available(
|
||||
gas, dst, (next_start + dialog_token) % 256))
|
||||
break;
|
||||
}
|
||||
if (dialog_token == 256)
|
||||
return -1; /* Too many pending queries */
|
||||
dialog_token = (next_start + dialog_token) % 256;
|
||||
next_start = (dialog_token + 1) % 256;
|
||||
return dialog_token;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_req - Request a GAS query
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
* @dst: Destination MAC address for the query
|
||||
* @freq: Frequency (in MHz) for the channel on which to send the query
|
||||
* @req: GAS query payload (to be freed by gas_query module in case of success
|
||||
* return)
|
||||
* @cb: Callback function for reporting GAS query result and response
|
||||
* @ctx: Context pointer to use with the @cb call
|
||||
* Returns: dialog token (>= 0) on success or -1 on failure
|
||||
*/
|
||||
int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
|
||||
struct wpabuf *req,
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code),
|
||||
void *ctx)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
int dialog_token;
|
||||
|
||||
if (!gas || wpabuf_len(req) < 3)
|
||||
return -1;
|
||||
|
||||
dialog_token = gas_query_new_dialog_token(gas, dst);
|
||||
if (dialog_token < 0)
|
||||
return -1;
|
||||
|
||||
query = os_zalloc(sizeof(*query));
|
||||
if (query == NULL)
|
||||
return -1;
|
||||
|
||||
query->gas = gas;
|
||||
os_memcpy(query->addr, dst, ETH_ALEN);
|
||||
query->dialog_token = dialog_token;
|
||||
query->freq = freq;
|
||||
query->cb = cb;
|
||||
query->ctx = ctx;
|
||||
query->req = req;
|
||||
dl_list_add(&gas->pending, &query->list);
|
||||
|
||||
*(wpabuf_mhead_u8(req) + 2) = dialog_token;
|
||||
|
||||
wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
|
||||
" dialog_token=%u freq=%d",
|
||||
MAC2STR(query->addr), query->dialog_token, query->freq);
|
||||
|
||||
gas_query_tx_initial_req(gas, query);
|
||||
|
||||
return dialog_token;
|
||||
}
|
43
contrib/wpa/src/ap/gas_query_ap.h
Normal file
43
contrib/wpa/src/ap/gas_query_ap.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) query
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011-2017, Qualcomm Atheros
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef GAS_QUERY_AP_H
|
||||
#define GAS_QUERY_AP_H
|
||||
|
||||
struct gas_query_ap;
|
||||
|
||||
struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
|
||||
void *msg_ctx);
|
||||
void gas_query_ap_deinit(struct gas_query_ap *gas);
|
||||
int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
|
||||
const u8 *data, size_t len, int freq);
|
||||
|
||||
/**
|
||||
* enum gas_query_ap_result - GAS query result
|
||||
*/
|
||||
enum gas_query_ap_result {
|
||||
GAS_QUERY_AP_SUCCESS,
|
||||
GAS_QUERY_AP_FAILURE,
|
||||
GAS_QUERY_AP_TIMEOUT,
|
||||
GAS_QUERY_AP_PEER_ERROR,
|
||||
GAS_QUERY_AP_INTERNAL_ERROR,
|
||||
GAS_QUERY_AP_DELETED_AT_DEINIT
|
||||
};
|
||||
|
||||
int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
|
||||
struct wpabuf *req,
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code),
|
||||
void *ctx);
|
||||
void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok);
|
||||
|
||||
#endif /* GAS_QUERY_AP_H */
|
@ -11,14 +11,31 @@
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/gas.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "gas_serv.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
static void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
|
||||
{
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 8); /* Length */
|
||||
wpabuf_put_u8(buf, 0x7f);
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 5);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, DPP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, 0x01);
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static void convert_to_protected_dual(struct wpabuf *msg)
|
||||
{
|
||||
u8 *categ = wpabuf_mhead_u8(msg);
|
||||
@ -50,9 +67,12 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
|
||||
sta->flags |= WLAN_STA_GAS;
|
||||
/*
|
||||
* The default inactivity is 300 seconds. We don't need
|
||||
* it to be that long.
|
||||
* it to be that long. Use five second timeout and increase this
|
||||
* with the comeback_delay for testing cases.
|
||||
*/
|
||||
ap_sta_session_timeout(hapd, sta, 5);
|
||||
ap_sta_session_timeout(hapd, sta,
|
||||
hapd->conf->gas_comeback_delay / 1024 +
|
||||
5);
|
||||
} else {
|
||||
ap_sta_replenish_timeout(hapd, sta, 5);
|
||||
}
|
||||
@ -161,8 +181,12 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
|
||||
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_osu_providers_nai_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
|
||||
if (hapd->conf->hs20_icons_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
|
||||
if (hapd->conf->hs20_operator_icon_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -255,20 +279,29 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
|
||||
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
|
||||
if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
|
||||
wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
|
||||
if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
|
||||
wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
|
||||
if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
|
||||
wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
|
||||
if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
|
||||
wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
|
||||
for (id = 273; id < 277; id++) {
|
||||
if (get_anqp_elem(hapd, id))
|
||||
wpabuf_put_le16(buf, id);
|
||||
}
|
||||
if (get_anqp_elem(hapd, ANQP_VENUE_URL))
|
||||
#ifdef CONFIG_FILS
|
||||
if (!dl_list_empty(&hapd->conf->fils_realms) ||
|
||||
get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
|
||||
wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
|
||||
#endif /* CONFIG_FILS */
|
||||
if (get_anqp_elem(hapd, ANQP_CAG))
|
||||
wpabuf_put_le16(buf, ANQP_CAG);
|
||||
if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
|
||||
wpabuf_put_le16(buf, ANQP_VENUE_URL);
|
||||
if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
|
||||
wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
|
||||
if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
|
||||
wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
|
||||
for (id = 280; id < 300; id++) {
|
||||
if (get_anqp_elem(hapd, id))
|
||||
wpabuf_put_le16(buf, id);
|
||||
}
|
||||
#ifdef CONFIG_HS20
|
||||
anqp_add_hs_capab_list(hapd, buf);
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -299,6 +332,29 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
|
||||
return;
|
||||
|
||||
if (hapd->conf->venue_url) {
|
||||
u8 *len;
|
||||
unsigned int i;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
|
||||
for (i = 0; i < hapd->conf->venue_url_count; i++) {
|
||||
struct hostapd_venue_url *url;
|
||||
|
||||
url = &hapd->conf->venue_url[i];
|
||||
wpabuf_put_u8(buf, 1 + url->url_len);
|
||||
wpabuf_put_u8(buf, url->venue_number);
|
||||
wpabuf_put_data(buf, url->url, url->url_len);
|
||||
}
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
@ -548,6 +604,36 @@ static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
|
||||
return;
|
||||
|
||||
count = dl_list_len(&hapd->conf->fils_realms);
|
||||
if (count > 10000)
|
||||
count = 10000;
|
||||
if (count) {
|
||||
struct fils_realm *realm;
|
||||
|
||||
wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
|
||||
wpabuf_put_le16(buf, 2 * count);
|
||||
|
||||
dl_list_for_each(realm, &hapd->conf->fils_realms,
|
||||
struct fils_realm, list) {
|
||||
if (count == 0)
|
||||
break;
|
||||
wpabuf_put_data(buf, realm->hash, 2);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
|
||||
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
|
||||
@ -621,6 +707,29 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
|
||||
const char *name)
|
||||
{
|
||||
size_t j;
|
||||
struct hs20_icon *icon = NULL;
|
||||
|
||||
for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
|
||||
if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
|
||||
icon = &bss->hs20_icons[j];
|
||||
}
|
||||
if (!icon)
|
||||
return; /* 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);
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_provider(struct wpabuf *buf,
|
||||
struct hostapd_bss_config *bss,
|
||||
struct hs20_osu_provider *p)
|
||||
@ -649,32 +758,14 @@ static void anqp_add_osu_provider(struct wpabuf *buf,
|
||||
|
||||
/* OSU Method List */
|
||||
count = wpabuf_put(buf, 1);
|
||||
for (i = 0; p->method_list[i] >= 0; i++)
|
||||
for (i = 0; p->method_list && 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);
|
||||
}
|
||||
for (i = 0; i < p->icons_count; i++)
|
||||
anqp_add_icon(buf, bss, p->icons[i]);
|
||||
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
|
||||
|
||||
/* OSU_NAI */
|
||||
@ -728,6 +819,40 @@ static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_provider_nai(struct wpabuf *buf,
|
||||
struct hs20_osu_provider *p)
|
||||
{
|
||||
/* OSU_NAI for shared BSS (Single SSID) */
|
||||
if (p->osu_nai2) {
|
||||
wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
|
||||
wpabuf_put_str(buf, p->osu_nai2);
|
||||
} else {
|
||||
wpabuf_put_u8(buf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->conf->hs20_osu_providers_nai_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_NAI_LIST);
|
||||
wpabuf_put_u8(buf, 0); /* Reserved */
|
||||
|
||||
for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
|
||||
anqp_add_osu_provider_nai(
|
||||
buf, &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)
|
||||
@ -783,9 +908,49 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
struct hostapd_bss_config *bss = hapd->conf;
|
||||
size_t i;
|
||||
u8 *len;
|
||||
|
||||
if (!bss->hs20_operator_icon_count)
|
||||
return;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
|
||||
wpabuf_put_u8(buf, 0); /* Reserved */
|
||||
|
||||
for (i = 0; i < bss->hs20_operator_icon_count; i++)
|
||||
anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
|
||||
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
static void anqp_add_mbo_cell_data_conn_pref(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->conf->mbo_cell_data_conn_pref >= 0) {
|
||||
u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, MBO_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
|
||||
wpabuf_put_u8(buf, hapd->conf->mbo_cell_data_conn_pref);
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
static size_t anqp_get_required_len(struct hostapd_data *hapd,
|
||||
const u16 *infoid,
|
||||
unsigned int num_infoid)
|
||||
@ -821,6 +986,10 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
len += 1000;
|
||||
if (request & ANQP_REQ_ICON_REQUEST)
|
||||
len += 65536;
|
||||
#ifdef CONFIG_FILS
|
||||
if (request & ANQP_FILS_REALM_INFO)
|
||||
len += 2 * dl_list_len(&hapd->conf->fils_realms);
|
||||
#endif /* CONFIG_FILS */
|
||||
len += anqp_get_required_len(hapd, extra_req, num_extra_req);
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
@ -860,8 +1029,19 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
if (request & ANQP_REQ_EMERGENCY_NAI)
|
||||
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
|
||||
|
||||
for (i = 0; i < num_extra_req; i++)
|
||||
for (i = 0; i < num_extra_req; i++) {
|
||||
#ifdef CONFIG_FILS
|
||||
if (extra_req[i] == ANQP_FILS_REALM_INFO) {
|
||||
anqp_add_fils_realm_info(hapd, buf);
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
if (extra_req[i] == ANQP_VENUE_URL) {
|
||||
anqp_add_venue_url(hapd, buf);
|
||||
continue;
|
||||
}
|
||||
anqp_add_elem(hapd, buf, extra_req[i]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
|
||||
@ -878,8 +1058,17 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
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);
|
||||
if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
|
||||
anqp_add_operator_icon_metadata(hapd, buf);
|
||||
if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
|
||||
anqp_add_osu_providers_nai_list(hapd, buf);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (request & ANQP_REQ_MBO_CELL_DATA_CONN_PREF)
|
||||
anqp_add_mbo_cell_data_conn_pref(hapd, buf);
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -984,7 +1173,17 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
default:
|
||||
if (!get_anqp_elem(hapd, info_id)) {
|
||||
#ifdef CONFIG_FILS
|
||||
if (info_id == ANQP_FILS_REALM_INFO &&
|
||||
!dl_list_empty(&hapd->conf->fils_realms)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: FILS Realm Information (local)");
|
||||
} else
|
||||
#endif /* CONFIG_FILS */
|
||||
if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: Venue URL (local)");
|
||||
} else if (!get_anqp_elem(hapd, info_id)) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
|
||||
info_id);
|
||||
break;
|
||||
@ -1050,6 +1249,16 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
|
||||
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
|
||||
hapd->conf->hs20_osu_providers_count, qi);
|
||||
break;
|
||||
case HS20_STYPE_OPERATOR_ICON_METADATA:
|
||||
set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
|
||||
"Operator Icon Metadata",
|
||||
hapd->conf->hs20_operator_icon_count, qi);
|
||||
break;
|
||||
case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
|
||||
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
|
||||
"OSU Providers NAI List",
|
||||
hapd->conf->hs20_osu_providers_nai_count, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
|
||||
subtype);
|
||||
@ -1092,49 +1301,12 @@ static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
static void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u32 oui;
|
||||
u8 subtype;
|
||||
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
|
||||
"Query element");
|
||||
return;
|
||||
}
|
||||
|
||||
oui = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
if (oui != OUI_WFA) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
|
||||
oui);
|
||||
return;
|
||||
}
|
||||
|
||||
#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);
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
|
||||
if (end - pos <= 1)
|
||||
return;
|
||||
|
||||
@ -1164,6 +1336,115 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
static void rx_anqp_vendor_specific_p2p(struct hostapd_data *hapd,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
/*
|
||||
* 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",
|
||||
P2P_OUI_TYPE);
|
||||
qi->p2p_sd = 1;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
static void rx_anqp_mbo_query_list(struct hostapd_data *hapd, u8 subtype,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
switch (subtype) {
|
||||
case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
|
||||
set_anqp_req(ANQP_REQ_MBO_CELL_DATA_CONN_PREF,
|
||||
"Cellular Data Connection Preference",
|
||||
hapd->conf->mbo_cell_data_conn_pref >= 0, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO subtype %u",
|
||||
subtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific_mbo(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u8 subtype;
|
||||
|
||||
if (end - pos < 1)
|
||||
return;
|
||||
|
||||
subtype = *pos++;
|
||||
switch (subtype) {
|
||||
case MBO_ANQP_SUBTYPE_QUERY_LIST:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: MBO Query List");
|
||||
while (pos < end) {
|
||||
rx_anqp_mbo_query_list(hapd, *pos, qi);
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO query subtype %u",
|
||||
subtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u32 oui;
|
||||
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
|
||||
"Query element");
|
||||
return;
|
||||
}
|
||||
|
||||
oui = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
if (oui != OUI_WFA) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
|
||||
oui);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (*pos) {
|
||||
#ifdef CONFIG_P2P
|
||||
case P2P_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_p2p(hapd, qi);
|
||||
break;
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_HS20
|
||||
case HS20_ANQP_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_hs20(hapd, pos + 1, end, qi);
|
||||
break;
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
case MBO_ANQP_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_mbo(hapd, pos + 1, end, qi);
|
||||
break;
|
||||
#endif /* CONFIG_MBO */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
|
||||
*pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
struct anqp_query_info *qi, int prot,
|
||||
@ -1189,7 +1470,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (wpabuf_len(buf) > hapd->gas_frag_limit ||
|
||||
if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
|
||||
hapd->conf->gas_comeback_delay) {
|
||||
struct gas_dialog_info *di;
|
||||
u16 comeback_delay = 1;
|
||||
@ -1240,6 +1521,72 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf)
|
||||
{
|
||||
struct wpabuf *tx_buf;
|
||||
|
||||
if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
|
||||
hapd->conf->gas_comeback_delay) {
|
||||
struct gas_dialog_info *di;
|
||||
u16 comeback_delay = 1;
|
||||
|
||||
if (hapd->conf->gas_comeback_delay) {
|
||||
/* Testing - allow overriding of the delay value */
|
||||
comeback_delay = hapd->conf->gas_comeback_delay;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Too long response to fit in initial response - use GAS comeback");
|
||||
di = gas_dialog_create(hapd, sa, dialog_token);
|
||||
if (!di) {
|
||||
wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
|
||||
MACSTR " (dialog token %u)",
|
||||
MAC2STR(sa), dialog_token);
|
||||
wpabuf_free(buf);
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
0, 10);
|
||||
if (tx_buf)
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
} else {
|
||||
di->prot = prot;
|
||||
di->sd_resp = buf;
|
||||
di->sd_resp_pos = 0;
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_SUCCESS,
|
||||
comeback_delay, 10);
|
||||
if (tx_buf)
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: GAS Initial response (no comeback)");
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_SUCCESS, 0,
|
||||
10 + 2 + wpabuf_len(buf));
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_le16(tx_buf, wpabuf_len(buf));
|
||||
wpabuf_put_buf(tx_buf, buf);
|
||||
hostapd_dpp_gas_status_handler(hapd, 1);
|
||||
}
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
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);
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
const u8 *sa,
|
||||
const u8 *data, size_t len, int prot,
|
||||
@ -1252,6 +1599,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
u16 slen;
|
||||
struct anqp_query_info qi;
|
||||
const u8 *adv_proto;
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp = 0;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (len < 1 + 2)
|
||||
return;
|
||||
@ -1279,6 +1629,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
|
||||
pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
|
||||
pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
|
||||
dpp = 1;
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
|
||||
struct wpabuf *buf;
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
@ -1318,6 +1677,18 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
end = pos + slen;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (dpp) {
|
||||
struct wpabuf *msg;
|
||||
|
||||
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
|
||||
if (!msg)
|
||||
return;
|
||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
/* ANQP Query Request */
|
||||
while (pos < end) {
|
||||
u16 info_id, elen;
|
||||
@ -1339,11 +1710,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
case ANQP_QUERY_LIST:
|
||||
rx_anqp_query_list(hapd, pos, pos + elen, &qi);
|
||||
break;
|
||||
#ifdef CONFIG_HS20
|
||||
case ANQP_VENDOR_SPECIFIC:
|
||||
rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
|
||||
break;
|
||||
#endif /* CONFIG_HS20 */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
|
||||
"Request element %u", info_id);
|
||||
@ -1393,8 +1762,8 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
|
||||
if (frag_len > hapd->gas_frag_limit) {
|
||||
frag_len = hapd->gas_frag_limit;
|
||||
if (frag_len > hapd->conf->gas_frag_limit) {
|
||||
frag_len = hapd->conf->gas_frag_limit;
|
||||
more = 1;
|
||||
}
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
|
||||
@ -1407,6 +1776,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
gas_serv_dialog_clear(dialog);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_DPP
|
||||
if (dialog->dpp) {
|
||||
tx_buf = gas_build_comeback_resp(dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
dialog->sd_frag_id, more, 0,
|
||||
10 + frag_len);
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_buf(tx_buf, buf);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
dialog->sd_frag_id,
|
||||
@ -1430,6 +1811,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
} else {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
|
||||
"SD response sent");
|
||||
#ifdef CONFIG_DPP
|
||||
if (dialog->dpp)
|
||||
hostapd_dpp_gas_status_handler(hapd, 1);
|
||||
#endif /* CONFIG_DPP */
|
||||
gas_serv_dialog_clear(dialog);
|
||||
gas_serv_free_dialogs(hapd, sa);
|
||||
}
|
||||
@ -1495,9 +1880,6 @@ int gas_serv_init(struct hostapd_data *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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#define ANQP_REQ_EMERGENCY_NAI \
|
||||
(1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
|
||||
/*
|
||||
* First 16 Hotspot 2.0 vendor specific ANQP-elements can be included in the
|
||||
* First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
|
||||
* optimized bitmap.
|
||||
*/
|
||||
#define ANQP_REQ_HS_CAPABILITY_LIST \
|
||||
@ -60,6 +60,13 @@
|
||||
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
|
||||
#define ANQP_REQ_ICON_REQUEST \
|
||||
(0x10000 << HS20_STYPE_ICON_REQUEST)
|
||||
#define ANQP_REQ_OPERATOR_ICON_METADATA \
|
||||
(0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA)
|
||||
#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \
|
||||
(0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST)
|
||||
/* The first MBO ANQP-element can be included in the optimized bitmap. */
|
||||
#define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \
|
||||
(BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
|
||||
|
||||
struct gas_dialog_info {
|
||||
u8 valid;
|
||||
@ -68,6 +75,7 @@ struct gas_dialog_info {
|
||||
size_t sd_resp_pos; /* Offset in sd_resp */
|
||||
u8 sd_frag_id;
|
||||
int prot; /* whether Protected Dual of Public Action frame is used */
|
||||
int dpp; /* whether this is a DPP Config Response */
|
||||
};
|
||||
|
||||
struct hostapd_data;
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "vlan_init.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "gas_query_ap.h"
|
||||
#include "hw_features.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
#include "ap_drv_ops.h"
|
||||
@ -45,6 +47,9 @@
|
||||
#include "ndisc_snoop.h"
|
||||
#include "neighbor_db.h"
|
||||
#include "rrm.h"
|
||||
#include "fils_hlp.h"
|
||||
#include "acs.h"
|
||||
#include "hs20.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
@ -52,6 +57,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
|
||||
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
|
||||
static int setup_interface2(struct hostapd_iface *iface);
|
||||
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
|
||||
|
||||
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
@ -71,10 +78,26 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
}
|
||||
|
||||
|
||||
void hostapd_reconfig_encryption(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->wpa_auth)
|
||||
return;
|
||||
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
hostapd_setup_encryption(hapd->conf->iface, hapd);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_reload_bss(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_ssid *ssid;
|
||||
|
||||
if (!hapd->started)
|
||||
return;
|
||||
|
||||
if (hapd->conf->wmm_enabled < 0)
|
||||
hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_client_reconfig(hapd->radius, hapd->conf->radius);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
@ -153,8 +176,27 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (newconf->num_bss != oldconf->num_bss)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < newconf->num_bss; i++) {
|
||||
if (os_strcmp(newconf->bss[i]->iface,
|
||||
oldconf->bss[i]->iface) != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = iface->interfaces;
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_config *newconf, *oldconf;
|
||||
size_t j;
|
||||
@ -177,6 +219,35 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
hostapd_clear_old(iface);
|
||||
|
||||
oldconf = hapd->iconf;
|
||||
if (hostapd_iface_conf_changed(newconf, oldconf)) {
|
||||
char *fname;
|
||||
int res;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Configuration changes include interface/BSS modification - force full disable+enable sequence");
|
||||
fname = os_strdup(iface->config_fname);
|
||||
if (!fname) {
|
||||
hostapd_config_free(newconf);
|
||||
return -1;
|
||||
}
|
||||
hostapd_remove_iface(interfaces, hapd->conf->iface);
|
||||
iface = hostapd_init(interfaces, fname);
|
||||
os_free(fname);
|
||||
hostapd_config_free(newconf);
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to initialize interface on config reload");
|
||||
return -1;
|
||||
}
|
||||
iface->interfaces = interfaces;
|
||||
interfaces->iface[interfaces->count] = iface;
|
||||
interfaces->count++;
|
||||
res = hostapd_enable_iface(iface);
|
||||
if (res < 0)
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to enable interface on config reload");
|
||||
return res;
|
||||
}
|
||||
iface->conf = newconf;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
@ -210,7 +281,7 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ifname)
|
||||
if (!ifname || !hapd->drv_priv)
|
||||
return;
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
|
||||
@ -297,6 +368,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
hostapd_deinit_wps(hapd);
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit(hapd);
|
||||
gas_query_ap_deinit(hapd->gas);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
authsrv_deinit(hapd);
|
||||
|
||||
@ -341,6 +416,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
hostapd_clean_rrm(hapd);
|
||||
fils_hlp_deinit(hapd);
|
||||
}
|
||||
|
||||
|
||||
@ -357,8 +433,10 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
|
||||
hapd->conf->iface);
|
||||
if (hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->ctrl_iface_deinit)
|
||||
hapd->iface->interfaces->ctrl_iface_deinit) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
|
||||
hapd->iface->interfaces->ctrl_iface_deinit(hapd);
|
||||
}
|
||||
hostapd_free_hapd_data(hapd);
|
||||
}
|
||||
|
||||
@ -387,8 +465,11 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
hostapd_stop_setup_timers(iface);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
if (iface->current_mode)
|
||||
acs_cleanup(iface);
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = NULL;
|
||||
iface->current_mode = NULL;
|
||||
os_free(iface->current_rates);
|
||||
iface->current_rates = NULL;
|
||||
os_free(iface->basic_rates);
|
||||
@ -409,6 +490,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
|
||||
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
|
||||
eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
|
||||
NULL);
|
||||
|
||||
hostapd_cleanup_iface_partial(iface);
|
||||
hostapd_config_free(iface->conf);
|
||||
@ -484,9 +567,12 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
if (hapd->conf && hapd->conf->broadcast_deauth) {
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
}
|
||||
hostapd_free_stas(hapd);
|
||||
|
||||
return ret;
|
||||
@ -873,6 +959,48 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||
return RADIUS_DAS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
static enum radius_das_res
|
||||
hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
int multi;
|
||||
|
||||
if (hostapd_das_nas_mismatch(hapd, attr))
|
||||
return RADIUS_DAS_NAS_MISMATCH;
|
||||
|
||||
sta = hostapd_das_find_sta(hapd, attr, &multi);
|
||||
if (!sta) {
|
||||
if (multi) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RADIUS DAS: Multiple sessions match - not supported");
|
||||
return RADIUS_DAS_MULTI_SESSION_MATCH;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
|
||||
return RADIUS_DAS_SESSION_NOT_FOUND;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
|
||||
" - CoA", MAC2STR(sta->addr));
|
||||
|
||||
if (attr->hs20_t_c_filtering) {
|
||||
if (attr->hs20_t_c_filtering[0] & BIT(0)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
|
||||
return RADIUS_DAS_COA_FAILED;
|
||||
}
|
||||
|
||||
hs20_t_c_filtering(hapd, sta, 0);
|
||||
}
|
||||
|
||||
return RADIUS_DAS_SUCCESS;
|
||||
}
|
||||
#else /* CONFIG_HS20 */
|
||||
#define hostapd_das_coa NULL
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
@ -956,13 +1084,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (conf->wmm_enabled < 0)
|
||||
conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (is_zero_ether_addr(conf->r1_key_holder))
|
||||
os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->iface->mconf == NULL)
|
||||
if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
|
||||
flush_old_stations = 0;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@ -1047,6 +1175,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
conf->radius_das_require_message_authenticator;
|
||||
das_conf.ctx = hapd;
|
||||
das_conf.disconnect = hostapd_das_disconnect;
|
||||
das_conf.coa = hostapd_das_coa;
|
||||
hapd->radius_das = radius_das_init(&das_conf);
|
||||
if (hapd->radius_das == NULL) {
|
||||
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
|
||||
@ -1063,6 +1192,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (hostapd_init_wps(hapd, conf))
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
|
||||
if (!hapd->gas)
|
||||
return -1;
|
||||
if (hostapd_dpp_init(hapd))
|
||||
return -1;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (authsrv_init(hapd) < 0)
|
||||
return -1;
|
||||
|
||||
@ -1150,7 +1287,7 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
|
||||
struct hostapd_tx_queue_params *p;
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf == NULL)
|
||||
if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
|
||||
return;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@ -1561,7 +1698,7 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
int center_freq1 = 0, center_freq2 = 0;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
enum nr_chan_width width;
|
||||
u32 bssid_info;
|
||||
struct wpabuf *nr;
|
||||
@ -1598,22 +1735,22 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
||||
ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel);
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return;
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht);
|
||||
if (vht) {
|
||||
center_freq1 = ieee80211_chan_to_freq(
|
||||
NULL, op_class,
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx);
|
||||
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2 = ieee80211_chan_to_freq(
|
||||
NULL, op_class,
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx);
|
||||
center_freq2_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
} else if (ht) {
|
||||
center_freq1 = hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel;
|
||||
ieee80211_freq_to_chan(hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel,
|
||||
¢er_freq1_idx);
|
||||
}
|
||||
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
@ -1641,17 +1778,127 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
|
||||
wpabuf_put_u8(nr, 3);
|
||||
wpabuf_put_u8(nr, width);
|
||||
wpabuf_put_u8(nr, center_freq1);
|
||||
wpabuf_put_u8(nr, center_freq2);
|
||||
wpabuf_put_u8(nr, center_freq1_idx);
|
||||
wpabuf_put_u8(nr, center_freq2_idx);
|
||||
|
||||
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
||||
hapd->iconf->civic);
|
||||
hapd->iconf->civic, hapd->iconf->stationary_ap);
|
||||
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
||||
static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
|
||||
if (os_strcmp(hapd->conf->owe_transition_ifname,
|
||||
bss->conf->iface) != 0)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: ifname=%s found transition mode ifname=%s BSSID "
|
||||
MACSTR " SSID %s",
|
||||
hapd->conf->iface, bss->conf->iface,
|
||||
MAC2STR(bss->own_addr),
|
||||
wpa_ssid_txt(bss->conf->ssid.ssid,
|
||||
bss->conf->ssid.ssid_len));
|
||||
if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
|
||||
is_zero_ether_addr(bss->own_addr))
|
||||
continue;
|
||||
|
||||
os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hapd->conf->owe_transition_ssid,
|
||||
bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
|
||||
hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Copied transition mode information");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->conf->owe_transition_ssid_len > 0 &&
|
||||
!is_zero_ether_addr(hapd->conf->owe_transition_bssid))
|
||||
return 0;
|
||||
|
||||
/* Find transition mode SSID/BSSID information from a BSS operated by
|
||||
* this hostapd instance. */
|
||||
if (!hapd->iface->interfaces ||
|
||||
!hapd->iface->interfaces->for_each_interface)
|
||||
return hostapd_owe_iface_iter(hapd->iface, hapd);
|
||||
else
|
||||
return hapd->iface->interfaces->for_each_interface(
|
||||
hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
int res;
|
||||
|
||||
if (!bss->conf->owe_transition_ifname[0])
|
||||
continue;
|
||||
res = hostapd_owe_trans_get_info(bss);
|
||||
if (res == 0)
|
||||
continue;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Matching transition mode interface enabled - update beacon data for %s",
|
||||
bss->conf->iface);
|
||||
ieee802_11_set_beacon(bss);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
static void hostapd_owe_update_trans(struct hostapd_iface *iface)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
/* Check whether the enabled BSS can complete OWE transition mode
|
||||
* configuration for any pending interface. */
|
||||
if (!iface->interfaces ||
|
||||
!iface->interfaces->for_each_interface)
|
||||
hostapd_owe_iface_iter2(iface, NULL);
|
||||
else
|
||||
iface->interfaces->for_each_interface(
|
||||
iface->interfaces, hostapd_owe_iface_iter2, NULL);
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_ctx;
|
||||
struct hostapd_data *hapd;
|
||||
|
||||
if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
|
||||
return;
|
||||
hapd = iface->bss[0];
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
int err)
|
||||
{
|
||||
@ -1827,6 +2074,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
|
||||
hostapd_owe_update_trans(iface);
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
@ -1851,8 +2099,19 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
iface->fst = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error)
|
||||
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error) {
|
||||
eloop_terminate();
|
||||
} else if (hapd->setup_complete_cb) {
|
||||
/*
|
||||
* Calling hapd->setup_complete_cb directly may cause iface
|
||||
* deinitialization which may be accessed later by the caller.
|
||||
*/
|
||||
eloop_register_timeout(0, 0,
|
||||
hostapd_interface_setup_failure_handler,
|
||||
iface, NULL);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1997,10 +2256,16 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
hapd->iconf = conf;
|
||||
hapd->conf = bss;
|
||||
hapd->iface = hapd_iface;
|
||||
hapd->driver = hapd->iconf->driver;
|
||||
if (conf)
|
||||
hapd->driver = conf->driver;
|
||||
hapd->ctrl_sock = -1;
|
||||
dl_list_init(&hapd->ctrl_dst);
|
||||
dl_list_init(&hapd->nr_db);
|
||||
hapd->dhcp_sock = -1;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
dl_list_init(&hapd->l2_queue);
|
||||
dl_list_init(&hapd->l2_oui_queue);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
return hapd;
|
||||
}
|
||||
@ -2028,12 +2293,6 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
|
||||
iface->wait_channel_update = 0;
|
||||
|
||||
@ -2049,6 +2308,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
break;
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
}
|
||||
|
||||
|
||||
@ -2402,6 +2668,11 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
|
||||
!!(hapd_iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
for (j = 0; j < hapd_iface->num_bss; j++)
|
||||
hostapd_cleanup_cs_params(hapd_iface->bss[j]);
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
|
||||
for (j = 0; j < hapd_iface->num_bss; j++) {
|
||||
struct hostapd_data *hapd = hapd_iface->bss[j];
|
||||
@ -2459,7 +2730,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
|
||||
if (conf == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
|
||||
"configuration", __func__);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver) {
|
||||
@ -2612,6 +2883,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
hostapd_owe_update_trans(hapd_iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2829,12 +3101,24 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
ieee802_1x_new_station(hapd, sta);
|
||||
if (reassoc) {
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK &&
|
||||
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
|
||||
} else
|
||||
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
|
||||
if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: %s: canceled wired ap_handle_timer timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, __func__,
|
||||
MAC2STR(sta->addr));
|
||||
}
|
||||
} else if (!(hapd->iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: %s: reschedule ap_handle_timer timeout for "
|
||||
MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
@ -2928,60 +3212,52 @@ static int hostapd_build_beacon_data(struct hostapd_data *hapd,
|
||||
goto free_ap_params;
|
||||
|
||||
ret = -1;
|
||||
beacon->head = os_malloc(params.head_len);
|
||||
beacon->head = os_memdup(params.head, params.head_len);
|
||||
if (!beacon->head)
|
||||
goto free_ap_extra_ies;
|
||||
|
||||
os_memcpy(beacon->head, params.head, params.head_len);
|
||||
beacon->head_len = params.head_len;
|
||||
|
||||
beacon->tail = os_malloc(params.tail_len);
|
||||
beacon->tail = os_memdup(params.tail, params.tail_len);
|
||||
if (!beacon->tail)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->tail, params.tail, params.tail_len);
|
||||
beacon->tail_len = params.tail_len;
|
||||
|
||||
if (params.proberesp != NULL) {
|
||||
beacon->probe_resp = os_malloc(params.proberesp_len);
|
||||
beacon->probe_resp = os_memdup(params.proberesp,
|
||||
params.proberesp_len);
|
||||
if (!beacon->probe_resp)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->probe_resp, params.proberesp,
|
||||
params.proberesp_len);
|
||||
beacon->probe_resp_len = params.proberesp_len;
|
||||
}
|
||||
|
||||
/* copy the extra ies */
|
||||
if (beacon_extra) {
|
||||
beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
|
||||
beacon->beacon_ies = os_memdup(beacon_extra->buf,
|
||||
wpabuf_len(beacon_extra));
|
||||
if (!beacon->beacon_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->beacon_ies,
|
||||
beacon_extra->buf, wpabuf_len(beacon_extra));
|
||||
beacon->beacon_ies_len = wpabuf_len(beacon_extra);
|
||||
}
|
||||
|
||||
if (proberesp_extra) {
|
||||
beacon->proberesp_ies =
|
||||
os_malloc(wpabuf_len(proberesp_extra));
|
||||
beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
|
||||
wpabuf_len(proberesp_extra));
|
||||
if (!beacon->proberesp_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
|
||||
wpabuf_len(proberesp_extra));
|
||||
beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
|
||||
}
|
||||
|
||||
if (assocresp_extra) {
|
||||
beacon->assocresp_ies =
|
||||
os_malloc(wpabuf_len(assocresp_extra));
|
||||
beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
|
||||
wpabuf_len(assocresp_extra));
|
||||
if (!beacon->assocresp_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
|
||||
wpabuf_len(assocresp_extra));
|
||||
beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
|
||||
}
|
||||
|
||||
@ -3158,6 +3434,19 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
|
||||
{
|
||||
if (vht_enabled)
|
||||
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
|
||||
else
|
||||
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
|
||||
hapd->iconf->ch_switch_vht_config);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings)
|
||||
{
|
||||
@ -3192,7 +3481,6 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
const struct hostapd_freq_params *freq_params)
|
||||
{
|
||||
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
|
||||
unsigned int i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
|
||||
|
||||
@ -3234,10 +3522,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
/*
|
||||
* cs_params must not be cleared earlier because the freq_params
|
||||
* argument may actually point to one of these.
|
||||
* These params will be cleared during interface disable below.
|
||||
*/
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
hostapd_cleanup_cs_params(iface->bss[i]);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
}
|
||||
|
@ -14,6 +14,13 @@
|
||||
#include "ap_config.h"
|
||||
#include "drivers/driver.h"
|
||||
|
||||
#define OCE_STA_CFON_ENABLED(hapd) \
|
||||
((hapd->conf->oce & OCE_STA_CFON) && \
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON))
|
||||
#define OCE_AP_ENABLED(hapd) \
|
||||
((hapd->conf->oce & OCE_AP) && \
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP))
|
||||
|
||||
struct wpa_ctrl_dst;
|
||||
struct radius_server_data;
|
||||
struct upnp_wps_device_sm;
|
||||
@ -53,7 +60,16 @@ struct hapd_interfaces {
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
struct dynamic_iface *vlan_priv;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
int eloop_initialized;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp_init_done;
|
||||
struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
|
||||
struct dl_list dpp_configurator; /* struct dpp_configurator */
|
||||
#endif /* CONFIG_DPP */
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@ -76,6 +92,7 @@ struct hostapd_rate_data {
|
||||
};
|
||||
|
||||
struct hostapd_frame_info {
|
||||
unsigned int freq;
|
||||
u32 channel;
|
||||
u32 datarate;
|
||||
int ssi_signal; /* dBm */
|
||||
@ -109,6 +126,7 @@ struct hostapd_neighbor_entry {
|
||||
struct wpabuf *civic;
|
||||
/* LCI update time */
|
||||
struct os_time lci_date;
|
||||
int stationary;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -184,6 +202,17 @@ struct hostapd_data {
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
struct l2_packet_data *l2;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct dl_list l2_queue;
|
||||
struct dl_list l2_oui_queue;
|
||||
struct eth_p_oui_ctx *oui_pull;
|
||||
struct eth_p_oui_ctx *oui_resp;
|
||||
struct eth_p_oui_ctx *oui_push;
|
||||
struct eth_p_oui_ctx *oui_sreq;
|
||||
struct eth_p_oui_ctx *oui_sresp;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
struct wps_context *wps;
|
||||
|
||||
int beacon_set_done;
|
||||
@ -242,9 +271,6 @@ struct hostapd_data {
|
||||
unsigned int cs_c_off_ecsa_beacon;
|
||||
unsigned int cs_c_off_ecsa_proberesp;
|
||||
|
||||
/* BSS Load */
|
||||
unsigned int bss_load_update_timeout;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
struct p2p_data *p2p;
|
||||
struct p2p_group *p2p_group;
|
||||
@ -259,9 +285,6 @@ struct hostapd_data {
|
||||
int noa_start;
|
||||
int noa_duration;
|
||||
#endif /* CONFIG_P2P */
|
||||
#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;
|
||||
@ -292,6 +315,18 @@ struct hostapd_data {
|
||||
unsigned int ext_eapol_frame_io:1;
|
||||
|
||||
struct l2_packet_data *l2_test;
|
||||
|
||||
enum wpa_alg last_gtk_alg;
|
||||
int last_gtk_key_idx;
|
||||
u8 last_gtk[WPA_GTK_MAX_LEN];
|
||||
size_t last_gtk_len;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum wpa_alg last_igtk_alg;
|
||||
int last_igtk_key_idx;
|
||||
u8 last_igtk[WPA_IGTK_MAX_LEN];
|
||||
size_t last_igtk_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
@ -300,10 +335,42 @@ struct hostapd_data {
|
||||
|
||||
struct dl_list nr_db;
|
||||
|
||||
u8 beacon_req_token;
|
||||
u8 lci_req_token;
|
||||
u8 range_req_token;
|
||||
unsigned int lci_req_active:1;
|
||||
unsigned int range_req_active:1;
|
||||
|
||||
int dhcp_sock; /* UDP socket used with the DHCP server */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp_init_done;
|
||||
struct dpp_authentication *dpp_auth;
|
||||
u8 dpp_allowed_roles;
|
||||
int dpp_qr_mutual;
|
||||
int dpp_auth_ok_on_ack;
|
||||
int dpp_in_response_listen;
|
||||
struct gas_query_ap *gas;
|
||||
struct dpp_pkex *dpp_pkex;
|
||||
struct dpp_bootstrap_info *dpp_pkex_bi;
|
||||
char *dpp_pkex_code;
|
||||
char *dpp_pkex_identifier;
|
||||
char *dpp_pkex_auth_cmd;
|
||||
char *dpp_configurator_params;
|
||||
struct os_reltime dpp_last_init;
|
||||
struct os_reltime dpp_init_iter_start;
|
||||
unsigned int dpp_init_max_tries;
|
||||
unsigned int dpp_init_retry_time;
|
||||
unsigned int dpp_resp_wait_time;
|
||||
unsigned int dpp_resp_max_tries;
|
||||
unsigned int dpp_resp_retry_time;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *dpp_config_obj_override;
|
||||
char *dpp_discovery_override;
|
||||
char *dpp_groups_override;
|
||||
unsigned int dpp_ignore_netaccesskey_mismatch:1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_DPP */
|
||||
};
|
||||
|
||||
|
||||
@ -311,6 +378,7 @@ struct hostapd_sta_info {
|
||||
struct dl_list list;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct os_reltime last_seen;
|
||||
int ssi_signal;
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
struct wpabuf *probe_ie_taxonomy;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
@ -440,6 +508,10 @@ struct hostapd_iface {
|
||||
u64 last_channel_time_busy;
|
||||
u8 channel_utilization;
|
||||
|
||||
unsigned int chan_util_samples_sum;
|
||||
unsigned int chan_util_num_sample_periods;
|
||||
unsigned int chan_util_average;
|
||||
|
||||
/* eCSA IE will be added only if operating class is specified */
|
||||
u8 cs_oper_class;
|
||||
|
||||
@ -459,6 +531,8 @@ struct hostapd_iface {
|
||||
|
||||
struct dl_list sta_seen; /* struct hostapd_sta_info */
|
||||
unsigned int num_sta_seen;
|
||||
|
||||
u8 dfs_domain;
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -466,6 +540,7 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
int (*cb)(struct hostapd_iface *iface,
|
||||
void *ctx), void *ctx);
|
||||
int hostapd_reload_config(struct hostapd_iface *iface);
|
||||
void hostapd_reconfig_encryption(struct hostapd_data *hapd);
|
||||
struct hostapd_data *
|
||||
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
struct hostapd_config *conf,
|
||||
@ -492,6 +567,7 @@ 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_csa_in_progress(struct hostapd_iface *iface);
|
||||
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
|
||||
int hostapd_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings);
|
||||
void
|
||||
@ -499,6 +575,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
const struct hostapd_freq_params *freq_params);
|
||||
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
@ -510,6 +587,8 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
|
||||
|
||||
/* drv_callbacks.c (TODO: move to somewhere else?) */
|
||||
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
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);
|
||||
@ -533,6 +612,9 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
|
||||
|
||||
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
|
||||
const char *ifname);
|
||||
void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
|
||||
enum smps_mode smps_mode,
|
||||
enum chan_width chan_width, u8 rx_nss);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
|
@ -11,9 +11,11 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
#include "hs20.h"
|
||||
|
||||
|
||||
@ -175,3 +177,72 @@ int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||
const u8 *addr, const char *url)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int ret;
|
||||
size_t url_len;
|
||||
|
||||
if (!url) {
|
||||
wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
url_len = os_strlen(url);
|
||||
if (5 + url_len > 255) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
|
||||
url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(4 + 7 + url_len);
|
||||
if (!buf)
|
||||
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 */
|
||||
|
||||
/* Terms and Conditions Acceptance subelement */
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 4 + 1 + url_len);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
|
||||
wpabuf_put_u8(buf, url_len);
|
||||
wpabuf_put_str(buf, url);
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions filtering required for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
sta->hs20_t_c_filtering = 1;
|
||||
/* TODO: Enable firewall filtering for the STA */
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions filtering not required for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
sta->hs20_t_c_filtering = 0;
|
||||
/* TODO: Disable firewall filtering for the STA */
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,9 @@ int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
|
||||
const u8 *addr,
|
||||
const struct wpabuf *payload);
|
||||
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||
const u8 *addr, const char *url);
|
||||
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int enabled);
|
||||
|
||||
#endif /* HS20_H */
|
||||
|
@ -78,10 +78,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
int i, j;
|
||||
u16 num_modes, flags;
|
||||
struct hostapd_hw_modes *modes;
|
||||
u8 dfs_domain;
|
||||
|
||||
if (hostapd_drv_none(hapd))
|
||||
return -1;
|
||||
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
|
||||
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags,
|
||||
&dfs_domain);
|
||||
if (modes == NULL) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -91,6 +93,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
iface->hw_flags = flags;
|
||||
iface->dfs_domain = dfs_domain;
|
||||
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = modes;
|
||||
@ -329,6 +332,9 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
|
||||
res = ieee80211n_allowed_ht40_channel_pair(iface);
|
||||
if (!res) {
|
||||
iface->conf->secondary_channel = 0;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx = 0;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx = 0;
|
||||
iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
res = 1;
|
||||
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
|
||||
}
|
||||
@ -621,41 +627,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||
|
||||
|
||||
#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;
|
||||
@ -683,45 +654,7 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
return ieee80211ac_cap_check(hw, conf);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
@ -746,7 +679,8 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
if (!ieee80211n_supported_ht_capab(iface))
|
||||
return -1;
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (!ieee80211ac_supported_vht_capab(iface))
|
||||
if (iface->conf->ieee80211ac &&
|
||||
!ieee80211ac_supported_vht_capab(iface))
|
||||
return -1;
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
ret = ieee80211n_check_40mhz(iface);
|
||||
@ -785,20 +719,41 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
|
||||
channel, primary ? "primary" : "secondary");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
int secondary_chan;
|
||||
|
||||
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);
|
||||
if (!iface->conf->ht40_plus_minus_allowed)
|
||||
return hostapd_is_usable_chan(
|
||||
iface, iface->conf->channel +
|
||||
iface->conf->secondary_channel * 4, 0);
|
||||
|
||||
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
|
||||
secondary_chan = iface->conf->channel + 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
iface->conf->secondary_channel = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
secondary_chan = iface->conf->channel - 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
iface->conf->secondary_channel = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -978,5 +933,19 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
|
||||
|
||||
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||
{
|
||||
return hw_get_chan(hapd->iface->current_mode, freq);
|
||||
int i, channel;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
channel = hw_get_chan(hapd->iface->current_mode, freq);
|
||||
if (channel)
|
||||
return channel;
|
||||
/* Check other available modes since the channel list for the current
|
||||
* mode did not include the specified frequency. */
|
||||
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||
mode = &hapd->iface->hw_features[i];
|
||||
channel = hw_get_chan(mode, freq);
|
||||
if (channel)
|
||||
return channel;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,8 @@ struct hostapd_frame_info;
|
||||
struct ieee80211_ht_capabilities;
|
||||
struct ieee80211_vht_capabilities;
|
||||
struct ieee80211_mgmt;
|
||||
struct vlan_description;
|
||||
struct hostapd_sta_wpa_psk_short;
|
||||
|
||||
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
struct hostapd_frame_info *fi);
|
||||
@ -55,6 +57,8 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
|
||||
int hostapd_ht_operation_update(struct hostapd_iface *iface);
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
@ -135,4 +139,31 @@ void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len);
|
||||
|
||||
u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid);
|
||||
void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
struct wpabuf *erp_resp,
|
||||
const u8 *msk, size_t msk_len);
|
||||
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *owe_dh, u8 owe_dh_len,
|
||||
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
|
||||
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
|
||||
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *pos, size_t len, u16 auth_alg,
|
||||
u16 auth_transaction, u16 status_code,
|
||||
void (*cb)(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
u16 resp, struct wpabuf *data, int pub));
|
||||
|
||||
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
|
||||
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
||||
|
@ -244,6 +244,7 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
|
||||
* @psk: Linked list buffer for returning WPA PSK
|
||||
* @identity: Buffer for returning identity (from RADIUS)
|
||||
* @radius_cui: Buffer for returning CUI (from RADIUS)
|
||||
* @is_probe_req: Whether this query for a Probe Request frame
|
||||
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
||||
*
|
||||
* The caller is responsible for freeing the returned *identity and *radius_cui
|
||||
@ -254,7 +255,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui)
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req)
|
||||
{
|
||||
int res;
|
||||
|
||||
@ -281,6 +283,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
#else /* CONFIG_NO_RADIUS */
|
||||
struct hostapd_acl_query_data *query;
|
||||
|
||||
if (is_probe_req) {
|
||||
/* Skip RADIUS queries for Probe Request frames to avoid
|
||||
* excessive load on the authentication server. */
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
};
|
||||
|
||||
/* Check whether ACL cache has an entry for this station */
|
||||
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval, vlan_id, psk,
|
||||
@ -327,14 +335,13 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
|
||||
query->auth_msg = os_malloc(len);
|
||||
query->auth_msg = os_memdup(msg, len);
|
||||
if (query->auth_msg == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||
"auth frame.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
os_memcpy(query->auth_msg, msg, len);
|
||||
query->auth_msg_len = len;
|
||||
query->next = hapd->acl_queries;
|
||||
hapd->acl_queries = query;
|
||||
@ -665,9 +672,11 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
hostapd_acl_cache_free(hapd->acl_cache);
|
||||
hapd->acl_cache = NULL;
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
query = hapd->acl_queries;
|
||||
hapd->acl_queries = NULL;
|
||||
while (query) {
|
||||
prev = query;
|
||||
query = query->next;
|
||||
|
@ -23,7 +23,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui);
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req);
|
||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
|
||||
|
88
contrib/wpa/src/ap/ieee802_11_he.c
Normal file
88
contrib/wpa/src/ap/ieee802_11_he.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11ax HE
|
||||
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_capabilities *cap;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
|
||||
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
|
||||
|
||||
cap = (struct ieee80211_he_capabilities *) pos;
|
||||
os_memset(cap, 0, sizeof(*cap));
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
|
||||
HE_PHYCAP_SU_BEAMFORMER_CAPAB;
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
|
||||
HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
|
||||
HE_PHYCAP_MU_BEAMFORMER_CAPAB;
|
||||
|
||||
pos += sizeof(*cap);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_operation *oper;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_operation);
|
||||
*pos++ = WLAN_EID_EXT_HE_OPERATION;
|
||||
|
||||
oper = (struct ieee80211_he_operation *) pos;
|
||||
os_memset(oper, 0, sizeof(*oper));
|
||||
|
||||
if (hapd->iface->conf->he_op.he_bss_color)
|
||||
oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
|
||||
|
||||
if (hapd->iface->conf->he_op.he_default_pe_duration)
|
||||
oper->he_oper_params |=
|
||||
(hapd->iface->conf->he_op.he_default_pe_duration <<
|
||||
HE_OPERATION_DFLT_PE_DURATION_OFFSET);
|
||||
|
||||
if (hapd->iface->conf->he_op.he_twt_required)
|
||||
oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
|
||||
|
||||
if (hapd->iface->conf->he_op.he_rts_threshold)
|
||||
oper->he_oper_params |=
|
||||
(hapd->iface->conf->he_op.he_rts_threshold <<
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET);
|
||||
|
||||
/* TODO: conditional MaxBSSID Indicator subfield */
|
||||
|
||||
pos += sizeof(*oper);
|
||||
|
||||
return pos;
|
||||
}
|
@ -236,17 +236,29 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
int i;
|
||||
const u8 *start = (const u8 *) mgmt;
|
||||
const u8 *data = start + IEEE80211_HDRLEN + 2;
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HT: Received 20/40 BSS Coexistence Management frame from "
|
||||
MACSTR, MAC2STR(mgmt->sa));
|
||||
|
||||
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))
|
||||
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
|
||||
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore too short 20/40 BSS Coexistence Management frame");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 20/40 BSS Coexistence element */
|
||||
bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
|
||||
if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
|
||||
bc_ie->length < 1) {
|
||||
@ -254,13 +266,35 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
bc_ie->element_id, bc_ie->length);
|
||||
return;
|
||||
}
|
||||
if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
|
||||
if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Truncated 20/40 BSS Coexistence element");
|
||||
return;
|
||||
}
|
||||
data += 2 + bc_ie->length;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
|
||||
bc_ie->coex_param);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
|
||||
bc_ie->coex_param,
|
||||
(bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
|
||||
(bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
|
||||
(bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
|
||||
(bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
|
||||
(bc_ie->coex_param & BIT(4)) ?
|
||||
"[OBSSScanExemptionGrant]" : "",
|
||||
(bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
|
||||
"[Reserved]" : "");
|
||||
|
||||
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
|
||||
/* Intra-BSS communication prohibiting 20/40 MHz BSS operation
|
||||
*/
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -269,6 +303,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
|
||||
/* Inter-BSS communication prohibiting 20/40 MHz BSS operation
|
||||
*/
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -276,12 +312,16 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
if (start + len - data >= 3 &&
|
||||
data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
|
||||
/* 20/40 BSS Intolerant Channel Report element (zero or more times) */
|
||||
while (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)
|
||||
if (ielen > start + len - data - 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Truncated 20/40 BSS Intolerant Channel Report element");
|
||||
return;
|
||||
}
|
||||
ic_report = (struct ieee80211_2040_intol_chan_report *) data;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"20/40 BSS Intolerant Channel Report: Operating Class %u",
|
||||
@ -292,8 +332,10 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
for (i = 0; i < ielen - 1; i++) {
|
||||
u8 chan = ic_report->variable[i];
|
||||
|
||||
if (chan == iface->conf->channel)
|
||||
continue; /* matching own primary channel */
|
||||
if (is_40_allowed(iface, chan))
|
||||
continue;
|
||||
continue; /* not within affected channels */
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -301,6 +343,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
chan);
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
data += 2 + ielen;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
|
||||
is_ht40_allowed, iface->num_sta_ht40_intolerant);
|
||||
@ -340,8 +384,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
* that did not specify a valid WMM IE in the (Re)Association Request
|
||||
* frame.
|
||||
*/
|
||||
if (!ht_capab ||
|
||||
!(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
|
||||
if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
|
||||
!hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
|
||||
sta->flags &= ~WLAN_STA_HT;
|
||||
os_free(sta->ht_capabilities);
|
||||
sta->ht_capabilities = NULL;
|
||||
|
@ -178,6 +178,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
case 1: /* Bits 8-15 */
|
||||
if (hapd->conf->proxy_arp)
|
||||
*pos |= 0x10; /* Bit 12 - Proxy ARP */
|
||||
if (hapd->conf->coloc_intf_reporting) {
|
||||
/* Bit 13 - Collocated Interference Reporting */
|
||||
*pos |= 0x20;
|
||||
}
|
||||
break;
|
||||
case 2: /* Bits 16-23 */
|
||||
if (hapd->conf->wnm_sleep_mode)
|
||||
@ -186,9 +190,9 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
||||
break;
|
||||
case 3: /* Bits 24-31 */
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
*pos |= 0x02; /* Bit 25 - SSID List */
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
if (hapd->conf->time_advertisement == 2)
|
||||
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
|
||||
if (hapd->conf->interworking)
|
||||
@ -218,12 +222,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
if (hapd->conf->ssid.utf8_ssid)
|
||||
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
|
||||
break;
|
||||
case 7: /* Bits 56-63 */
|
||||
break;
|
||||
case 8: /* Bits 64-71 */
|
||||
if (hapd->conf->ftm_responder)
|
||||
*pos |= 0x40; /* Bit 70 - FTM responder */
|
||||
if (hapd->conf->ftm_initiator)
|
||||
*pos |= 0x80; /* Bit 71 - FTM initiator */
|
||||
break;
|
||||
case 9: /* Bits 72-79 */
|
||||
#ifdef CONFIG_FILS
|
||||
if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
|
||||
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
|
||||
*pos |= 0x01;
|
||||
#endif /* CONFIG_FILS */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,10 +259,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
if (len < 9 &&
|
||||
(hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
|
||||
len = 9;
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (len < 4)
|
||||
len = 4;
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
#ifdef CONFIG_HS20
|
||||
if (hapd->conf->hs20 && len < 6)
|
||||
len = 6;
|
||||
@ -258,6 +271,11 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
if (hapd->conf->mbo_enabled && len < 6)
|
||||
len = 6;
|
||||
#endif /* CONFIG_MBO */
|
||||
#ifdef CONFIG_FILS
|
||||
if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
|
||||
len = 10;
|
||||
#endif /* CONFIG_FILS */
|
||||
if (len < hapd->iface->extended_capa_len)
|
||||
len = hapd->iface->extended_capa_len;
|
||||
if (len == 0)
|
||||
@ -432,7 +450,7 @@ u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (hapd->conf->time_advertisement != 2)
|
||||
if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
|
||||
return eid;
|
||||
|
||||
len = os_strlen(hapd->conf->time_zone);
|
||||
@ -503,7 +521,7 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (hapd->conf->ap_max_inactivity > 0) {
|
||||
unsigned int val;
|
||||
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
|
||||
@ -521,7 +539,7 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
pos += 2;
|
||||
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
|
||||
}
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -531,23 +549,38 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 mbo[6], *mbo_pos = mbo;
|
||||
u8 mbo[9], *mbo_pos = mbo;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
if (!hapd->conf->mbo_enabled &&
|
||||
!OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
return eid;
|
||||
|
||||
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
/* Not Cellular aware */
|
||||
*mbo_pos++ = 0;
|
||||
if (hapd->conf->mbo_enabled) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
/* Not Cellular aware */
|
||||
*mbo_pos++ = 0;
|
||||
}
|
||||
|
||||
if (hapd->mbo_assoc_disallow) {
|
||||
if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = hapd->mbo_assoc_disallow;
|
||||
}
|
||||
|
||||
if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
|
||||
u8 ctrl;
|
||||
|
||||
ctrl = OCE_RELEASE;
|
||||
if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
ctrl |= OCE_IS_STA_CFON;
|
||||
|
||||
*mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = ctrl;
|
||||
}
|
||||
|
||||
pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
|
||||
|
||||
return pos;
|
||||
@ -556,19 +589,91 @@ u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
|
||||
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
u8 len;
|
||||
|
||||
if (!hapd->conf->mbo_enabled &&
|
||||
!OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* MBO IE header (6) + Capability Indication attribute (3) +
|
||||
* Association Disallowed attribute (3) = 12
|
||||
*/
|
||||
return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
|
||||
len = 6;
|
||||
if (hapd->conf->mbo_enabled)
|
||||
len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
|
||||
|
||||
/* OCE capability indication attribute (3) */
|
||||
if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
|
||||
len += 3;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
|
||||
{
|
||||
return hapd->conf->owe_transition_ssid_len > 0 &&
|
||||
!is_zero_ether_addr(hapd->conf->owe_transition_bssid);
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
if (!hostapd_eid_owe_trans_enabled(hapd))
|
||||
return 0;
|
||||
return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
|
||||
#else /* CONFIG_OWE */
|
||||
return 0;
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
u8 *pos = eid;
|
||||
size_t elen;
|
||||
|
||||
if (hapd->conf->owe_transition_ifname[0] &&
|
||||
!hostapd_eid_owe_trans_enabled(hapd))
|
||||
hostapd_owe_trans_get_info(hapd);
|
||||
|
||||
if (!hostapd_eid_owe_trans_enabled(hapd))
|
||||
return pos;
|
||||
|
||||
elen = hostapd_eid_owe_trans_len(hapd);
|
||||
if (len < elen) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Not enough room in the buffer for OWE IE");
|
||||
return pos;
|
||||
}
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = elen - 2;
|
||||
WPA_PUT_BE24(pos, OUI_WFA);
|
||||
pos += 3;
|
||||
*pos++ = OWE_OUI_TYPE;
|
||||
os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
*pos++ = hapd->conf->owe_transition_ssid_len;
|
||||
os_memcpy(pos, hapd->conf->owe_transition_ssid,
|
||||
hapd->conf->owe_transition_ssid_len);
|
||||
pos += hapd->conf->owe_transition_ssid_len;
|
||||
|
||||
return pos;
|
||||
#else /* CONFIG_OWE */
|
||||
return eid;
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len)
|
||||
@ -584,3 +689,66 @@ void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
|
||||
supp_op_classes_len);
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
#ifdef CONFIG_FILS
|
||||
u8 *len;
|
||||
u16 fils_info = 0;
|
||||
size_t realms;
|
||||
struct fils_realm *realm;
|
||||
|
||||
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
|
||||
return pos;
|
||||
|
||||
realms = dl_list_len(&hapd->conf->fils_realms);
|
||||
if (realms > 7)
|
||||
realms = 7; /* 3 bit count field limits this to max 7 */
|
||||
|
||||
*pos++ = WLAN_EID_FILS_INDICATION;
|
||||
len = pos++;
|
||||
/* TODO: B0..B2: Number of Public Key Identifiers */
|
||||
if (hapd->conf->erp_domain) {
|
||||
/* B3..B5: Number of Realm Identifiers */
|
||||
fils_info |= realms << 3;
|
||||
}
|
||||
/* TODO: B6: FILS IP Address Configuration */
|
||||
if (hapd->conf->fils_cache_id_set)
|
||||
fils_info |= BIT(7);
|
||||
if (hessid && !is_zero_ether_addr(hapd->conf->hessid))
|
||||
fils_info |= BIT(8); /* HESSID Included */
|
||||
/* FILS Shared Key Authentication without PFS Supported */
|
||||
fils_info |= BIT(9);
|
||||
if (hapd->conf->fils_dh_group) {
|
||||
/* FILS Shared Key Authentication with PFS Supported */
|
||||
fils_info |= BIT(10);
|
||||
}
|
||||
/* TODO: B11: FILS Public Key Authentication Supported */
|
||||
/* B12..B15: Reserved */
|
||||
WPA_PUT_LE16(pos, fils_info);
|
||||
pos += 2;
|
||||
if (hapd->conf->fils_cache_id_set) {
|
||||
os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN);
|
||||
pos += FILS_CACHE_ID_LEN;
|
||||
}
|
||||
if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) {
|
||||
os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
}
|
||||
|
||||
dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
|
||||
list) {
|
||||
if (realms == 0)
|
||||
break;
|
||||
realms--;
|
||||
os_memcpy(pos, realm->hash, 2);
|
||||
pos += 2;
|
||||
}
|
||||
*len = pos - len - 1;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
{
|
||||
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
|
||||
if (!vht_capab ||
|
||||
hapd->conf->disable_11ac ||
|
||||
!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
|
||||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
|
||||
sta->flags &= ~WLAN_STA_VHT;
|
||||
os_free(sta->vht_capabilities);
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "hs20.h"
|
||||
/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_1x.h"
|
||||
|
||||
|
||||
@ -316,6 +318,7 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
|
||||
hdr->code != EAP_CODE_INITIATE))
|
||||
return;
|
||||
|
||||
eap_erp_update_identity(sm->eap, eap, len);
|
||||
identity = eap_get_identity(sm->eap, &identity_len);
|
||||
if (identity == NULL)
|
||||
return;
|
||||
@ -472,7 +475,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
|
||||
sta->wpa_sm &&
|
||||
(wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
|
||||
@ -485,7 +488,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
|
||||
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
|
||||
@ -588,9 +591,9 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *eap, size_t len)
|
||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *eap, size_t len)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
@ -680,6 +683,8 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_HS20
|
||||
if (hapd->conf->hs20) {
|
||||
u8 ver = 1; /* Release 2 */
|
||||
if (HS20_VERSION > 0x10)
|
||||
ver = 2; /* Release 3 */
|
||||
if (!radius_msg_add_wfa(
|
||||
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
|
||||
&ver, 1)) {
|
||||
@ -709,6 +714,41 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta->roaming_consortium &&
|
||||
!radius_msg_add_wfa(
|
||||
msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
|
||||
wpabuf_head(sta->roaming_consortium),
|
||||
wpabuf_len(sta->roaming_consortium))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Could not add HS 2.0 Roaming Consortium");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hapd->conf->t_c_filename) {
|
||||
be32 timestamp;
|
||||
|
||||
if (!radius_msg_add_wfa(
|
||||
msg,
|
||||
RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
|
||||
(const u8 *) hapd->conf->t_c_filename,
|
||||
os_strlen(hapd->conf->t_c_filename))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Could not add HS 2.0 T&C Filename");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
timestamp = host_to_be32(hapd->conf->t_c_timestamp);
|
||||
if (!radius_msg_add_wfa(
|
||||
msg,
|
||||
RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
|
||||
(const u8 *) ×tamp,
|
||||
sizeof(timestamp))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Could not add HS 2.0 Timestamp");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
@ -845,7 +885,7 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_state_machine *
|
||||
struct eapol_state_machine *
|
||||
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int flags = 0;
|
||||
@ -970,7 +1010,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
}
|
||||
|
||||
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
|
||||
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
|
||||
if (key_mgmt != -1 &&
|
||||
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
|
||||
key_mgmt == WPA_KEY_MGMT_DPP)) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
|
||||
"STA is using PSK");
|
||||
return;
|
||||
@ -1113,7 +1155,9 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
|
||||
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
|
||||
if (key_mgmt != -1 &&
|
||||
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
|
||||
key_mgmt == WPA_KEY_MGMT_DPP)) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
|
||||
/*
|
||||
* Clear any possible EAPOL authenticator state to support
|
||||
@ -1154,7 +1198,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
sta->eapol_sm->eap_if->portEnabled = TRUE;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -1170,10 +1214,32 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
/* TODO: get vlan_id from R0KH using RRB message */
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"PMK from FILS - skip IEEE 802.1X/EAP");
|
||||
/* Setup EAPOL state machines to already authenticated state
|
||||
* because of existing FILS information. */
|
||||
sta->eapol_sm->keyRun = TRUE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
|
||||
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
|
||||
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
|
||||
if (pmksa) {
|
||||
@ -1395,11 +1461,10 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
|
||||
}
|
||||
} while (class_len < 1);
|
||||
|
||||
nclass[nclass_count].data = os_malloc(class_len);
|
||||
nclass[nclass_count].data = os_memdup(attr_class, class_len);
|
||||
if (nclass[nclass_count].data == NULL)
|
||||
break;
|
||||
|
||||
os_memcpy(nclass[nclass_count].data, attr_class, class_len);
|
||||
nclass[nclass_count].len = class_len;
|
||||
nclass_count++;
|
||||
}
|
||||
@ -1559,6 +1624,33 @@ static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
|
||||
ap_sta_session_warning_timeout(hapd, sta, warning_time);
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *pos,
|
||||
size_t len)
|
||||
{
|
||||
if (len < 4)
|
||||
return; /* Malformed information */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
|
||||
pos[0], pos[1], pos[2], pos[3]);
|
||||
hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *pos, size_t len)
|
||||
{
|
||||
os_free(sta->t_c_url);
|
||||
sta->t_c_url = os_malloc(len + 1);
|
||||
if (!sta->t_c_url)
|
||||
return;
|
||||
os_memcpy(sta->t_c_url, pos, len);
|
||||
sta->t_c_url[len] = '\0';
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
@ -1606,6 +1698,12 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
|
||||
ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
|
||||
session_timeout);
|
||||
break;
|
||||
case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
|
||||
ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
|
||||
break;
|
||||
case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
|
||||
ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -1663,6 +1761,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct sta_info *sta;
|
||||
u32 session_timeout = 0, termination_action, acct_interim_interval;
|
||||
int session_timeout_set;
|
||||
u32 reason_code;
|
||||
struct eapol_state_machine *sm;
|
||||
int override_eapReq = 0;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
@ -1788,14 +1887,17 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
break;
|
||||
|
||||
sta->session_timeout_set = !!session_timeout_set;
|
||||
sta->session_timeout = session_timeout;
|
||||
os_get_reltime(&sta->session_timeout);
|
||||
sta->session_timeout.sec += session_timeout;
|
||||
|
||||
/* RFC 3580, Ch. 3.17 */
|
||||
if (session_timeout_set && termination_action ==
|
||||
RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
|
||||
RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
|
||||
sm->reAuthPeriod = session_timeout;
|
||||
} else if (session_timeout_set)
|
||||
else if (session_timeout_set)
|
||||
ap_sta_session_timeout(hapd, sta, session_timeout);
|
||||
else
|
||||
ap_sta_no_session_timeout(hapd, sta);
|
||||
|
||||
sm->eap_if->aaaSuccess = TRUE;
|
||||
override_eapReq = 1;
|
||||
@ -1811,6 +1913,13 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
case RADIUS_CODE_ACCESS_REJECT:
|
||||
sm->eap_if->aaaFail = TRUE;
|
||||
override_eapReq = 1;
|
||||
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
|
||||
&reason_code) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
|
||||
MACSTR, reason_code, MAC2STR(sta->addr));
|
||||
sta->disconnect_reason_code = reason_code;
|
||||
}
|
||||
break;
|
||||
case RADIUS_CODE_ACCESS_CHALLENGE:
|
||||
sm->eap_if->aaaEapReq = TRUE;
|
||||
@ -1837,6 +1946,19 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
if (override_eapReq)
|
||||
sm->eap_if->aaaEapReq = FALSE;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
#ifdef NEED_AP_MLME
|
||||
if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
|
||||
/* TODO: Add a PMKSA entry on success? */
|
||||
ieee802_11_finish_fils_auth(
|
||||
hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
|
||||
sm->eap_if->aaaEapReqData,
|
||||
sm->eap_if->aaaEapKeyData,
|
||||
sm->eap_if->aaaEapKeyDataLen);
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
eapol_auth_step(sm);
|
||||
|
||||
return RADIUS_RX_QUEUED;
|
||||
@ -1924,7 +2046,7 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
|
||||
eapol->default_wep_key_idx);
|
||||
|
||||
|
||||
if (ieee802_1x_rekey_broadcast(hapd)) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_WARNING, "failed to generate a "
|
||||
@ -2034,13 +2156,19 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
|
||||
}
|
||||
|
||||
if (eap_user->password) {
|
||||
user->password = os_malloc(eap_user->password_len);
|
||||
user->password = os_memdup(eap_user->password,
|
||||
eap_user->password_len);
|
||||
if (user->password == NULL)
|
||||
goto out;
|
||||
os_memcpy(user->password, eap_user->password,
|
||||
eap_user->password_len);
|
||||
user->password_len = eap_user->password_len;
|
||||
user->password_hash = eap_user->password_hash;
|
||||
if (eap_user->salt && eap_user->salt_len) {
|
||||
user->salt = os_memdup(eap_user->salt,
|
||||
eap_user->salt_len);
|
||||
if (!user->salt)
|
||||
goto out;
|
||||
user->salt_len = eap_user->salt_len;
|
||||
}
|
||||
}
|
||||
user->force_version = eap_user->force_version;
|
||||
user->macacl = eap_user->macacl;
|
||||
@ -2190,6 +2318,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
conf.erp_domain = hapd->conf->erp_domain;
|
||||
conf.erp = hapd->conf->eap_server_erp;
|
||||
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
conf.tls_flags = hapd->conf->tls_flags;
|
||||
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
|
||||
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
|
||||
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
|
||||
@ -2326,6 +2455,16 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
MAC2STR(sta->addr), xhdr->version, xhdr->type,
|
||||
be_to_host16(xhdr->length), ack);
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
|
||||
(sta->flags & WLAN_STA_WPS) &&
|
||||
ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPS: Indicate EAP completion on ACK for EAP-Failure");
|
||||
hostapd_wps_eap_completed(hapd);
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
|
||||
return 0;
|
||||
|
||||
@ -2642,6 +2781,15 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
|
||||
hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
|
||||
sta->hs20_deauth_req);
|
||||
}
|
||||
|
||||
if (sta->hs20_t_c_filtering) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
|
||||
MACSTR " to indicate Terms and Conditions filtering",
|
||||
MAC2STR(sta->addr));
|
||||
hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
|
||||
os_free(sta->t_c_url);
|
||||
sta->t_c_url = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
@ -2655,6 +2803,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
/* TODO: get PMKLifetime from WPA parameters */
|
||||
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||
unsigned int session_timeout;
|
||||
struct os_reltime now, remaining;
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (remediation && !sta->remediation) {
|
||||
@ -2665,7 +2814,8 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
sta->remediation_method = 1; /* SOAP-XML SPP */
|
||||
}
|
||||
|
||||
if (success && (sta->remediation || sta->hs20_deauth_req)) {
|
||||
if (success && (sta->remediation || sta->hs20_deauth_req ||
|
||||
sta->hs20_t_c_filtering)) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
|
||||
MACSTR " in 100 ms", MAC2STR(sta->addr));
|
||||
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
|
||||
@ -2675,10 +2825,13 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
key = ieee802_1x_get_key(sta->eapol_sm, &len);
|
||||
if (sta->session_timeout_set)
|
||||
session_timeout = sta->session_timeout;
|
||||
else
|
||||
if (sta->session_timeout_set) {
|
||||
os_get_reltime(&now);
|
||||
os_reltime_sub(&sta->session_timeout, &now, &remaining);
|
||||
session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
|
||||
} else {
|
||||
session_timeout = dot11RSNAConfigPMKLifetime;
|
||||
}
|
||||
if (success && key && len >= PMK_LEN && !sta->remediation &&
|
||||
!sta->hs20_deauth_requested &&
|
||||
wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
|
||||
@ -2699,15 +2852,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
* EAP-FAST with anonymous provisioning, may require another
|
||||
* EAPOL authentication to be started to complete connection.
|
||||
*/
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
|
||||
"disconnection after EAP-Failure");
|
||||
/* Add a small sleep to increase likelihood of previously
|
||||
* requested EAP-Failure TX getting out before this should the
|
||||
* driver reorder operations.
|
||||
*/
|
||||
os_sleep(0, 10000);
|
||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||
WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
|
||||
hostapd_wps_eap_completed(hapd);
|
||||
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
|
||||
}
|
||||
}
|
||||
|
@ -57,5 +57,10 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
struct hostapd_radius_attr *req_attr,
|
||||
struct sta_info *sta,
|
||||
struct radius_msg *msg);
|
||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *eap, size_t len);
|
||||
struct eapol_state_machine *
|
||||
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
#endif /* IEEE802_1X_H */
|
||||
|
@ -182,4 +182,5 @@ int ndisc_snoop_init(struct hostapd_data *hapd)
|
||||
void ndisc_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
l2_packet_deinit(hapd->sock_ndisc);
|
||||
hapd->sock_ndisc = NULL;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
|
||||
nr->civic = NULL;
|
||||
os_memset(nr->bssid, 0, sizeof(nr->bssid));
|
||||
os_memset(&nr->ssid, 0, sizeof(nr->ssid));
|
||||
nr->stationary = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +65,7 @@ hostapd_neighbor_add(struct hostapd_data *hapd)
|
||||
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
const struct wpabuf *nr, const struct wpabuf *lci,
|
||||
const struct wpabuf *civic)
|
||||
const struct wpabuf *civic, int stationary)
|
||||
{
|
||||
struct hostapd_neighbor_entry *entry;
|
||||
|
||||
@ -83,18 +84,20 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
if (!entry->nr)
|
||||
goto fail;
|
||||
|
||||
if (lci) {
|
||||
if (lci && wpabuf_len(lci)) {
|
||||
entry->lci = wpabuf_dup(lci);
|
||||
if (!entry->lci || os_get_time(&entry->lci_date))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (civic) {
|
||||
if (civic && wpabuf_len(civic)) {
|
||||
entry->civic = wpabuf_dup(civic);
|
||||
if (!entry->civic)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
entry->stationary = stationary;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@ -16,7 +16,7 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
|
||||
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
const struct wpabuf *nr, const struct wpabuf *lci,
|
||||
const struct wpabuf *civic);
|
||||
const struct wpabuf *civic, int stationary);
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid);
|
||||
void hostpad_free_neighbor_db(struct hostapd_data *hapd);
|
||||
|
@ -1,396 +0,0 @@
|
||||
/*
|
||||
* hostapd - PeerKey for Direct Link Setup (DLS)
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_i.h"
|
||||
#include "wpa_auth_ie.h"
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
|
||||
static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
#if 0
|
||||
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||
struct wpa_stsl_negotiation *neg = timeout_ctx;
|
||||
#endif
|
||||
|
||||
/* TODO: ? */
|
||||
}
|
||||
|
||||
|
||||
struct wpa_stsl_search {
|
||||
const u8 *addr;
|
||||
struct wpa_state_machine *sm;
|
||||
};
|
||||
|
||||
|
||||
static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
|
||||
{
|
||||
struct wpa_stsl_search *search = ctx;
|
||||
if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
|
||||
search->sm = sm;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, const u8 *peer,
|
||||
u16 mui, u16 error_type)
|
||||
{
|
||||
u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
|
||||
u8 *pos;
|
||||
struct rsn_error_kde error;
|
||||
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK Error");
|
||||
|
||||
pos = kde;
|
||||
|
||||
if (peer) {
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
error.mui = host_to_be16(mui);
|
||||
error.error_type = host_to_be16(error_type);
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
|
||||
(u8 *) &error, sizeof(error), NULL, 0);
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
|
||||
NULL, NULL, kde, pos - kde, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
|
||||
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(key_data, key_data_len, &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
|
||||
kde.mac_addr_len < ETH_ALEN) {
|
||||
wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
|
||||
"SMK M1");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initiator = sm->addr; Peer = kde.mac_addr */
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||
" aborted - STA not associated anymore",
|
||||
MAC2STR(kde.mac_addr));
|
||||
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||
STK_ERR_STA_NR);
|
||||
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||
return;
|
||||
}
|
||||
|
||||
buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
|
||||
buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
/* Initiator RSN IE */
|
||||
os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
|
||||
pos = buf + kde.rsn_ie_len;
|
||||
/* Initiator MAC Address */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
|
||||
NULL, 0);
|
||||
|
||||
/* SMK M2:
|
||||
* EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||
* MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
|
||||
*/
|
||||
|
||||
wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M2");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, search.sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_eapol_key *key,
|
||||
struct wpa_eapol_ie_parse *kde,
|
||||
const u8 *smk)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
u32 lifetime;
|
||||
|
||||
/* SMK M4:
|
||||
* EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
|
||||
* MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
|
||||
* Lifetime KDE)
|
||||
*/
|
||||
|
||||
buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||
pos = buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
/* Initiator MAC Address */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
|
||||
NULL, 0);
|
||||
|
||||
/* Initiator Nonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
|
||||
NULL, 0);
|
||||
|
||||
/* SMK with PNonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||
key->key_nonce, WPA_NONCE_LEN);
|
||||
|
||||
/* Lifetime */
|
||||
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M4");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_eapol_key *key,
|
||||
struct wpa_eapol_ie_parse *kde,
|
||||
const u8 *smk, const u8 *peer)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
u32 lifetime;
|
||||
|
||||
/* SMK M5:
|
||||
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||
* MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
|
||||
* Lifetime KDE))
|
||||
*/
|
||||
|
||||
buf_len = kde->rsn_ie_len +
|
||||
2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||
pos = buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
/* Peer RSN IE */
|
||||
os_memcpy(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);
|
||||
|
||||
/* PNonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
|
||||
WPA_NONCE_LEN, NULL, 0);
|
||||
|
||||
/* SMK and INonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||
kde->nonce, WPA_NONCE_LEN);
|
||||
|
||||
/* Lifetime */
|
||||
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M5");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, struct wpa_eapol_key *key,
|
||||
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(key_data, key_data_len, &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.rsn_ie == NULL ||
|
||||
kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||
kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
|
||||
wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
|
||||
"Nonce KDE in SMK M3");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Peer = sm->addr; Initiator = kde.mac_addr;
|
||||
* Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||
" aborted - STA not associated anymore",
|
||||
MAC2STR(kde.mac_addr));
|
||||
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||
STK_ERR_STA_NR);
|
||||
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||
return;
|
||||
}
|
||||
|
||||
if (random_get_bytes(smk, PMK_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* SMK = PRF-256(Random number, "SMK Derivation",
|
||||
* AA || Time || INonce || PNonce)
|
||||
*/
|
||||
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
|
||||
pos = buf + ETH_ALEN;
|
||||
wpa_get_ntp_timestamp(pos);
|
||||
pos += 8;
|
||||
os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
|
||||
pos += WPA_NONCE_LEN;
|
||||
os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
|
||||
smk, PMK_LEN);
|
||||
#else /* CONFIG_IEEE80211W */
|
||||
sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
|
||||
smk, PMK_LEN);
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
|
||||
|
||||
wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
|
||||
wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
|
||||
|
||||
/* Authenticator does not need SMK anymore and it is required to forget
|
||||
* it. */
|
||||
os_memset(smk, 0, sizeof(*smk));
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
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(key_data, key_data_len, &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||
kde.error == NULL || kde.error_len < sizeof(error)) {
|
||||
wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
|
||||
"SMK Error");
|
||||
return;
|
||||
}
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
|
||||
"associated for SMK Error message from " MACSTR,
|
||||
MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(&error, kde.error, sizeof(error));
|
||||
mui = be_to_host16(error.mui);
|
||||
error_type = be_to_host16(error.error_type);
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"STA reported SMK Error: Peer " MACSTR
|
||||
" MUI %d Error Type %d",
|
||||
MAC2STR(kde.mac_addr), mui, error_type);
|
||||
|
||||
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
|
||||
}
|
||||
|
||||
|
||||
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_stsl_negotiation *neg)
|
||||
{
|
||||
struct wpa_stsl_negotiation *pos, *prev;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return -1;
|
||||
pos = wpa_auth->stsl_negotiations;
|
||||
prev = NULL;
|
||||
while (pos) {
|
||||
if (pos == neg) {
|
||||
if (prev)
|
||||
prev->next = pos->next;
|
||||
else
|
||||
wpa_auth->stsl_negotiations = pos->next;
|
||||
|
||||
eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
|
||||
os_free(pos);
|
||||
return 0;
|
||||
}
|
||||
prev = pos;
|
||||
pos = pos->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PEERKEY */
|
@ -282,7 +282,42 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *entry, *pos;
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
|
||||
entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
|
||||
aa, spa, session_timeout, eapol,
|
||||
akmp);
|
||||
|
||||
if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
|
||||
return NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_auth_create_entry - Create a PMKSA cache entry
|
||||
* @pmk: The new pairwise master key
|
||||
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
|
||||
* @pmkid: Calculated PMKID
|
||||
* @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
|
||||
* @eapol: Pointer to EAPOL state machine data
|
||||
* @akmp: WPA_KEY_MGMT_* used in key derivation
|
||||
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
|
||||
*
|
||||
* This function creates a PMKSA entry.
|
||||
*/
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
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;
|
||||
struct os_reltime now;
|
||||
|
||||
if (pmk_len > PMK_LEN_MAX)
|
||||
@ -303,8 +338,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
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));
|
||||
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
|
||||
os_get_reltime(&now);
|
||||
entry->expiration = now.sec;
|
||||
if (session_timeout > 0)
|
||||
@ -315,9 +349,30 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
os_memcpy(entry->spa, spa, ETH_ALEN);
|
||||
pmksa_cache_from_eapol_data(entry, eapol);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_auth_add_entry - Add a PMKSA cache entry
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
* @entry: Pointer to PMKSA cache entry
|
||||
*
|
||||
* This function adds PMKSA cache entry to the PMKSA cache. If an old entry is
|
||||
* already in the cache for the same Supplicant, this entry will be replaced
|
||||
* with the new entry. PMKID will be calculated based on the PMK.
|
||||
*/
|
||||
int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *pos;
|
||||
|
||||
if (entry == NULL)
|
||||
return -1;
|
||||
|
||||
/* Replace an old entry for the same STA (if found) with the new entry
|
||||
*/
|
||||
pos = pmksa_cache_auth_get(pmksa, spa, NULL);
|
||||
pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL);
|
||||
if (pos)
|
||||
pmksa_cache_free_entry(pmksa, pos);
|
||||
|
||||
@ -331,7 +386,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
|
||||
pmksa_cache_link_entry(pmksa, entry);
|
||||
|
||||
return entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -462,7 +517,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
|
||||
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));
|
||||
entry->akmp);
|
||||
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
|
||||
return entry;
|
||||
}
|
||||
@ -605,3 +660,70 @@ int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
|
||||
}
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
|
||||
#ifdef CONFIG_MESH
|
||||
|
||||
/**
|
||||
* pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
* @addr: MAC address of the peer (NULL means any)
|
||||
* @buf: Buffer for the list
|
||||
* @len: Length of the buffer
|
||||
* Returns: Number of bytes written to buffer
|
||||
*
|
||||
* This function is used to generate a text format representation of the
|
||||
* current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store
|
||||
* in external storage.
|
||||
*/
|
||||
int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
char *pos, *end;
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
struct os_reltime now;
|
||||
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
os_get_reltime(&now);
|
||||
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <BSSID> <PMKID> <PMK> <expiration in seconds>
|
||||
*/
|
||||
for (entry = pmksa->pmksa; entry; entry = entry->next) {
|
||||
if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
|
||||
continue;
|
||||
|
||||
ret = os_snprintf(pos, end - pos, MACSTR " ",
|
||||
MAC2STR(entry->spa));
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return 0;
|
||||
pos += ret;
|
||||
|
||||
pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid,
|
||||
PMKID_LEN);
|
||||
|
||||
ret = os_snprintf(pos, end - pos, " ");
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return 0;
|
||||
pos += ret;
|
||||
|
||||
pos += wpa_snprintf_hex(pos, end - pos, entry->pmk,
|
||||
entry->pmk_len);
|
||||
|
||||
ret = os_snprintf(pos, end - pos, " %d\n",
|
||||
(int) (entry->expiration - now.sec));
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return 0;
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
@ -35,6 +35,7 @@ struct rsn_pmksa_cache_entry {
|
||||
};
|
||||
|
||||
struct rsn_pmksa_cache;
|
||||
struct radius_das_attrs;
|
||||
|
||||
struct rsn_pmksa_cache *
|
||||
pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
@ -53,6 +54,13 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
const u8 *kck, size_t kck_len, const u8 *aa,
|
||||
const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp);
|
||||
int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
|
||||
const struct rsn_pmksa_cache_entry *old_entry,
|
||||
const u8 *aa, const u8 *pmkid);
|
||||
@ -65,5 +73,7 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
|
||||
struct radius_das_attrs *attr);
|
||||
int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
|
||||
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
|
||||
int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
|
||||
char *buf, size_t len);
|
||||
|
||||
#endif /* PMKSA_CACHE_H */
|
||||
|
@ -2,6 +2,7 @@
|
||||
* hostapd / Radio Measurement (RRM)
|
||||
* Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
|
||||
* Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -10,6 +11,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
@ -69,24 +71,47 @@ static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
|
||||
const u8 *addr, u8 token, u8 rep_mode,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
char report[2 * 255 + 1];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
|
||||
token, len, MAC2STR(addr));
|
||||
/* Skip to the beginning of the Beacon report */
|
||||
if (len < 3)
|
||||
return;
|
||||
pos += 3;
|
||||
len -= 3;
|
||||
report[0] = '\0';
|
||||
if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
|
||||
return;
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
|
||||
MAC2STR(addr), token, rep_mode, report);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
const u8 *pos, *ie, *end;
|
||||
u8 token;
|
||||
u8 token, rep_mode;
|
||||
|
||||
end = buf + len;
|
||||
token = mgmt->u.action.u.rrm.dialog_token;
|
||||
pos = mgmt->u.action.u.rrm.variable;
|
||||
|
||||
while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
|
||||
if (ie[1] < 5) {
|
||||
if (ie[1] < 3) {
|
||||
wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Measurement report type %u", ie[4]);
|
||||
rep_mode = ie[3];
|
||||
wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
|
||||
rep_mode, ie[4]);
|
||||
|
||||
switch (ie[4]) {
|
||||
case MEASURE_TYPE_LCI:
|
||||
@ -95,6 +120,10 @@ static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
|
||||
case MEASURE_TYPE_FTM_RANGE:
|
||||
hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
|
||||
break;
|
||||
case MEASURE_TYPE_BEACON:
|
||||
hostapd_handle_beacon_report(hapd, mgmt->sa, token,
|
||||
rep_mode, ie + 2, ie[1]);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Measurement report type %u is not supported",
|
||||
@ -118,7 +147,7 @@ static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
|
||||
/* Subelements are arranged as IEs */
|
||||
subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
|
||||
if (subelem && subelem[1] == 2)
|
||||
return *(u16 *) (subelem + 2);
|
||||
return WPA_GET_LE16(subelem + 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -129,12 +158,12 @@ static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
|
||||
struct os_time curr, diff;
|
||||
unsigned long diff_l;
|
||||
|
||||
if (nr->stationary || max_age == 0xffff)
|
||||
return 1;
|
||||
|
||||
if (!max_age)
|
||||
return 0;
|
||||
|
||||
if (max_age == 0xffff)
|
||||
return 1;
|
||||
|
||||
if (os_get_time(&curr))
|
||||
return 0;
|
||||
|
||||
@ -341,13 +370,7 @@ int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
int ret;
|
||||
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request LCI: Destination address is not in station list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request LCI: Destination address is not connected");
|
||||
return -1;
|
||||
@ -450,9 +473,8 @@ int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Request range: Range request is already in process; overriding");
|
||||
hapd->range_req_active = 0;
|
||||
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
|
||||
hostapd_range_rep_timeout_handler, hapd,
|
||||
NULL);
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Action + measurement type + token + reps + EID + len = 7 */
|
||||
@ -542,3 +564,111 @@ void hostapd_clean_rrm(struct hostapd_data *hapd)
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
hapd->range_req_active = 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
u8 req_mode, const struct wpabuf *req)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
int ret;
|
||||
enum beacon_report_mode mode;
|
||||
const u8 *pos;
|
||||
|
||||
/* Request data:
|
||||
* Operating Class (1), Channel Number (1), Randomization Interval (2),
|
||||
* Measurement Duration (2), Measurement Mode (1), BSSID (6),
|
||||
* Optional Subelements (variable)
|
||||
*/
|
||||
if (wpabuf_len(req) < 13) {
|
||||
wpa_printf(MSG_INFO, "Beacon request: Too short request data");
|
||||
return -1;
|
||||
}
|
||||
pos = wpabuf_head(req);
|
||||
mode = pos[6];
|
||||
|
||||
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Beacon request: " MACSTR " is not connected",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case BEACON_REPORT_MODE_PASSIVE:
|
||||
if (!(sta->rrm_enabled_capa[0] &
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Beacon request: " MACSTR
|
||||
" does not support passive beacon report",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case BEACON_REPORT_MODE_ACTIVE:
|
||||
if (!(sta->rrm_enabled_capa[0] &
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Beacon request: " MACSTR
|
||||
" does not support active beacon report",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case BEACON_REPORT_MODE_TABLE:
|
||||
if (!(sta->rrm_enabled_capa[0] &
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Beacon request: " MACSTR
|
||||
" does not support table beacon report",
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO,
|
||||
"Beacon request: Unknown measurement mode %d", mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
hapd->beacon_req_token++;
|
||||
if (!hapd->beacon_req_token)
|
||||
hapd->beacon_req_token++;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||
wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
|
||||
wpabuf_put_u8(buf, hapd->beacon_req_token);
|
||||
wpabuf_put_le16(buf, 0); /* Number of repetitions */
|
||||
|
||||
/* Measurement Request element */
|
||||
wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
|
||||
wpabuf_put_u8(buf, 3 + wpabuf_len(req));
|
||||
wpabuf_put_u8(buf, 1); /* Measurement Token */
|
||||
wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
|
||||
wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
|
||||
wpabuf_put_buf(buf, req);
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return hapd->beacon_req_token;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len, int ok)
|
||||
{
|
||||
if (len < 24 + 3)
|
||||
return;
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
|
||||
" %u ack=%d", MAC2STR(mgmt->da),
|
||||
mgmt->u.action.u.rrm.dialog_token, ok);
|
||||
}
|
||||
|
@ -24,5 +24,10 @@ int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 random_interval, u8 min_ap,
|
||||
const u8 *responders, unsigned int n_responders);
|
||||
void hostapd_clean_rrm(struct hostapd_data *hapd);
|
||||
int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
u8 req_mode, const struct wpabuf *req);
|
||||
void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len, int ok);
|
||||
|
||||
#endif /* RRM_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -17,6 +17,7 @@
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "fst/fst.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "hostapd.h"
|
||||
#include "accounting.h"
|
||||
#include "ieee802_1x.h"
|
||||
@ -36,6 +37,7 @@
|
||||
#include "ndisc_snoop.h"
|
||||
#include "sta_info.h"
|
||||
#include "vlan.h"
|
||||
#include "wps_hostapd.h"
|
||||
|
||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
@ -47,6 +49,7 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
@ -194,7 +197,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
if (sta->no_short_slot_time_set) {
|
||||
sta->no_short_slot_time_set = 0;
|
||||
hapd->iface->num_sta_no_short_slot_time--;
|
||||
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
&& hapd->iface->num_sta_no_short_slot_time == 0)
|
||||
set_beacon++;
|
||||
}
|
||||
@ -202,7 +206,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
if (sta->no_short_preamble_set) {
|
||||
sta->no_short_preamble_set = 0;
|
||||
hapd->iface->num_sta_no_short_preamble--;
|
||||
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
&& hapd->iface->num_sta_no_short_preamble == 0)
|
||||
set_beacon++;
|
||||
}
|
||||
@ -316,6 +321,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
wpabuf_free(sta->wps_ie);
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
wpabuf_free(sta->hs20_ie);
|
||||
wpabuf_free(sta->roaming_consortium);
|
||||
#ifdef CONFIG_FST
|
||||
wpabuf_free(sta->mb_ies);
|
||||
#endif /* CONFIG_FST */
|
||||
@ -326,6 +332,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
os_free(sta->remediation_url);
|
||||
os_free(sta->t_c_url);
|
||||
wpabuf_free(sta->hs20_deauth_req);
|
||||
os_free(sta->hs20_session_info_url);
|
||||
|
||||
@ -337,6 +344,31 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
mbo_ap_sta_free(sta);
|
||||
os_free(sta->supp_op_classes);
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
wpabuf_free(sta->fils_hlp_resp);
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
crypto_ecdh_deinit(sta->fils_ecdh);
|
||||
wpabuf_clear_free(sta->fils_dh_ss);
|
||||
wpabuf_free(sta->fils_g_sta);
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
bin_clear_free(sta->owe_pmk, sta->owe_pmk_len);
|
||||
crypto_ecdh_deinit(sta->owe_ecdh);
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
os_free(sta->ext_capability);
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
os_free(sta->ifname_wds);
|
||||
|
||||
os_free(sta);
|
||||
}
|
||||
|
||||
@ -597,7 +629,7 @@ 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
|
||||
#ifdef CONFIG_WNM_AP
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
@ -608,7 +640,7 @@ static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
|
||||
sta->hs20_disassoc_timer);
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
}
|
||||
|
||||
|
||||
@ -745,9 +777,17 @@ 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->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
||||
/* Skip deauthentication in DMG/IEEE 802.11ad */
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
||||
WLAN_STA_ASSOC_REQ_OK);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
} else {
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
}
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
|
||||
@ -783,6 +823,14 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
||||
/* Deauthentication is not used in DMG/IEEE 802.11ad;
|
||||
* disassociate the STA instead. */
|
||||
ap_sta_disassociate(hapd, sta, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
@ -1229,6 +1277,20 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
ap_handle_timer, hapd, sta);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
|
||||
/* Deauthentication is not used in DMG/IEEE 802.11ad;
|
||||
* disassociate the STA instead. */
|
||||
sta->disassoc_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
||||
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
||||
eloop_register_timeout(hapd->iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
|
||||
2 : 0, 0, ap_sta_disassoc_cb_timeout,
|
||||
hapd, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
sta->deauth_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
|
||||
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||
@ -1275,6 +1337,15 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
||||
"%s: Removed ap_sta_disassoc_cb_timeout timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (sta->flags & WLAN_STA_WPS)
|
||||
hostapd_wps_eap_completed(hapd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1283,7 +1354,7 @@ 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",
|
||||
res = os_snprintf(buf, buflen, "%s%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]" : ""),
|
||||
@ -1300,6 +1371,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
(flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
|
||||
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
|
||||
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
|
||||
(flags & WLAN_STA_HT ? "[HT]" : ""),
|
||||
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
|
||||
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
|
||||
(flags & WLAN_STA_WNM_SLEEP_MODE ?
|
||||
@ -1309,3 +1381,48 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
u16 reason;
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"IEEE 802.1X: Scheduled disconnection of " MACSTR
|
||||
" after EAP-Failure", MAC2STR(sta->addr));
|
||||
|
||||
reason = sta->disconnect_reason_code;
|
||||
if (!reason)
|
||||
reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
|
||||
ap_sta_disconnect(hapd, sta, sta->addr, reason);
|
||||
if (sta->flags & WLAN_STA_WPS)
|
||||
hostapd_wps_eap_completed(hapd);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"IEEE 802.1X: Force disconnection of " MACSTR
|
||||
" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
|
||||
|
||||
/*
|
||||
* Add a small sleep to increase likelihood of previously requested
|
||||
* EAP-Failure TX getting out before this should the driver reorder
|
||||
* operations.
|
||||
*/
|
||||
eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
|
||||
eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
|
||||
hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
|
||||
hapd, sta);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -9,14 +9,11 @@
|
||||
#ifndef STA_INFO_H
|
||||
#define STA_INFO_H
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
/* needed for mesh_plink_state enum */
|
||||
#include "common/defs.h"
|
||||
#include "common/wpa_common.h"
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
#include "list.h"
|
||||
#include "vlan.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
@ -38,6 +35,7 @@
|
||||
#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_FILS_ERP BIT(22)
|
||||
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
|
||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||
#define WLAN_STA_NONERP BIT(31)
|
||||
@ -46,6 +44,7 @@
|
||||
* Supported Rates IEs). */
|
||||
#define WLAN_SUPP_RATES_MAX 32
|
||||
|
||||
struct hostapd_data;
|
||||
|
||||
struct mbo_non_pref_chan_info {
|
||||
struct mbo_non_pref_chan_info *next;
|
||||
@ -68,6 +67,7 @@ struct sta_info {
|
||||
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 */
|
||||
u16 disconnect_reason_code; /* RADIUS server override */
|
||||
u32 flags; /* Bitfield of WLAN_STA_* */
|
||||
u16 capability;
|
||||
u16 listen_interval; /* or beacon_int for APs */
|
||||
@ -113,6 +113,10 @@ struct sta_info {
|
||||
unsigned int radius_das_match:1;
|
||||
unsigned int ecsa_supported:1;
|
||||
unsigned int added_unassoc:1;
|
||||
unsigned int pending_wds_enable:1;
|
||||
unsigned int power_capab:1;
|
||||
unsigned int agreed_to_steer:1;
|
||||
unsigned int hs20_t_c_filtering:1;
|
||||
|
||||
u16 auth_alg;
|
||||
|
||||
@ -170,17 +174,20 @@ struct sta_info {
|
||||
struct os_reltime sa_query_start;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
|
||||
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
|
||||
struct gas_dialog_info *gas_dialog;
|
||||
u8 gas_dialog_next;
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#endif /* CONFIG_INTERWORKING || CONFIG_DPP */
|
||||
|
||||
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 */
|
||||
/* Hotspot 2.0 Roaming Consortium from (Re)Association Request */
|
||||
struct wpabuf *roaming_consortium;
|
||||
u8 remediation_method;
|
||||
char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
|
||||
char *t_c_url; /* HS 2.0 Terms and Conditions Server URL */
|
||||
struct wpabuf *hs20_deauth_req;
|
||||
char *hs20_session_info_url;
|
||||
int hs20_disassoc_timer;
|
||||
@ -195,7 +202,8 @@ struct sta_info {
|
||||
unsigned int mesh_sae_pmksa_caching:1;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
u32 session_timeout; /* valid only if session_timeout_set == 1 */
|
||||
/* valid only if session_timeout_set == 1 */
|
||||
struct os_reltime session_timeout;
|
||||
|
||||
/* Last Authentication/(Re)Association Request/Action frame sequence
|
||||
* control */
|
||||
@ -214,10 +222,51 @@ struct sta_info {
|
||||
|
||||
u8 rrm_enabled_capa[5];
|
||||
|
||||
s8 min_tx_power;
|
||||
s8 max_tx_power;
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
struct wpabuf *probe_ie_taxonomy;
|
||||
struct wpabuf *assoc_ie_taxonomy;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
u8 fils_snonce[FILS_NONCE_LEN];
|
||||
u8 fils_session[FILS_SESSION_LEN];
|
||||
u8 fils_erp_pmkid[PMKID_LEN];
|
||||
u8 *fils_pending_assoc_req;
|
||||
size_t fils_pending_assoc_req_len;
|
||||
unsigned int fils_pending_assoc_is_reassoc:1;
|
||||
unsigned int fils_dhcp_rapid_commit_proxy:1;
|
||||
unsigned int fils_erp_pmkid_set:1;
|
||||
unsigned int fils_drv_assoc_finish:1;
|
||||
struct wpabuf *fils_hlp_resp;
|
||||
struct wpabuf *hlp_dhcp_discover;
|
||||
void (*fils_pending_cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 resp, struct wpabuf *data, int pub);
|
||||
#ifdef CONFIG_FILS_SK_PFS
|
||||
struct crypto_ecdh *fils_ecdh;
|
||||
#endif /* CONFIG_FILS_SK_PFS */
|
||||
struct wpabuf *fils_dh_ss;
|
||||
struct wpabuf *fils_g_sta;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
u8 *owe_pmk;
|
||||
size_t owe_pmk_len;
|
||||
struct crypto_ecdh *owe_ecdh;
|
||||
u16 owe_group;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
u8 *ext_capability;
|
||||
char *ifname_wds; /* WDS ifname, if in use */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
enum wpa_alg last_tk_alg;
|
||||
int last_tk_key_idx;
|
||||
u8 last_tk[WPA_TK_MAX_LEN];
|
||||
size_t last_tk_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
|
||||
@ -237,8 +286,6 @@ struct sta_info {
|
||||
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
|
||||
|
||||
|
||||
struct hostapd_data;
|
||||
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void *ctx),
|
||||
@ -289,5 +336,9 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
|
||||
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
#endif /* STA_INFO_H */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "taxonomy.h"
|
||||
|
||||
|
||||
/* Copy a string with no funny schtuff allowed; only alphanumerics. */
|
||||
|
@ -71,6 +71,11 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
|
||||
struct os_reltime now;
|
||||
int ret = 0;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Michael MIC failure detected in received frame%s",
|
||||
local ? " (local)" : "");
|
||||
|
||||
if (addr && local) {
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
if (sta != NULL) {
|
||||
|
@ -138,6 +138,8 @@ int vlan_init(struct hostapd_data *hapd)
|
||||
!hapd->conf->vlan) {
|
||||
/* dynamic vlans enabled but no (or empty) vlan_file given */
|
||||
struct hostapd_vlan *vlan;
|
||||
int ret;
|
||||
|
||||
vlan = os_zalloc(sizeof(*vlan));
|
||||
if (vlan == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Out of memory while assigning "
|
||||
@ -146,8 +148,16 @@ int vlan_init(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
vlan->vlan_id = VLAN_ID_WILDCARD;
|
||||
os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
|
||||
hapd->conf->iface);
|
||||
ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
|
||||
hapd->conf->iface);
|
||||
if (ret >= (int) sizeof(vlan->ifname)) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"VLAN: Interface name was truncated to %s",
|
||||
vlan->ifname);
|
||||
} else if (ret < 0) {
|
||||
os_free(vlan);
|
||||
return ret;
|
||||
}
|
||||
vlan->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = vlan;
|
||||
}
|
||||
|
@ -21,11 +21,6 @@
|
||||
#include "wmm.h"
|
||||
|
||||
|
||||
/* TODO: maintain separate sequence and fragment numbers for each AC
|
||||
* TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
|
||||
* if only WMM stations are receiving a certain group */
|
||||
|
||||
|
||||
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
|
||||
{
|
||||
u8 ret;
|
||||
@ -157,8 +152,9 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
int wmm_process_tspec(struct wmm_tspec_element *tspec)
|
||||
{
|
||||
int medium_time, pps, duration;
|
||||
int up, psb, dir, tid;
|
||||
u64 medium_time;
|
||||
unsigned int pps, duration;
|
||||
unsigned int up, psb, dir, tid;
|
||||
u16 val, surplus;
|
||||
|
||||
up = (tspec->ts_info[1] >> 3) & 0x07;
|
||||
@ -206,8 +202,9 @@ int wmm_process_tspec(struct wmm_tspec_element *tspec)
|
||||
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
|
||||
}
|
||||
|
||||
medium_time = surplus * pps * duration / 0x2000;
|
||||
wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
|
||||
medium_time = (u64) surplus * pps * duration / 0x2000;
|
||||
wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %lu",
|
||||
(unsigned long) medium_time);
|
||||
|
||||
/*
|
||||
* TODO: store list of granted (and still active) TSPECs and check
|
||||
|
@ -95,8 +95,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
if (mgmt == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
|
||||
"WNM-Sleep Response action frame");
|
||||
os_free(wnmtfs_ie);
|
||||
return -1;
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
@ -109,6 +109,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
|
||||
/* add key data if MFP is enabled */
|
||||
if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
|
||||
hapd->conf->wnm_sleep_mode_no_keys ||
|
||||
action_type != WNM_SLEEP_MODE_EXIT) {
|
||||
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
|
||||
} else {
|
||||
@ -118,11 +119,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
(int) gtk_elem_len);
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
|
||||
if (res < 0) {
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(mgmt);
|
||||
return -1;
|
||||
}
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
igtk_elem_len = res;
|
||||
pos += igtk_elem_len;
|
||||
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
|
||||
@ -176,7 +174,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
wpa_set_wnmsleep(sta->wpa_sm, 0);
|
||||
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
|
||||
addr, NULL, NULL);
|
||||
if (!wpa_auth_uses_mfp(sta->wpa_sm))
|
||||
if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
|
||||
hapd->conf->wnm_sleep_mode_no_keys)
|
||||
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
|
||||
}
|
||||
} else
|
||||
@ -184,6 +183,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
|
||||
#undef MAX_GTK_SUBELEM_LEN
|
||||
#undef MAX_IGTK_SUBELEM_LEN
|
||||
fail:
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(mgmt);
|
||||
return res;
|
||||
@ -202,12 +202,20 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
u8 *tfsreq_ie_end = NULL;
|
||||
u16 tfsreq_ie_len = 0;
|
||||
|
||||
if (!hapd->conf->wnm_sleep_mode) {
|
||||
wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
|
||||
MACSTR " since WNM-Sleep Mode is disabled",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
dialog_token = *pos++;
|
||||
while (pos + 1 < frm + len) {
|
||||
u8 ie_len = pos[1];
|
||||
if (pos + 2 + ie_len > frm + len)
|
||||
break;
|
||||
if (*pos == WLAN_EID_WNMSLEEP)
|
||||
if (*pos == WLAN_EID_WNMSLEEP &&
|
||||
ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
|
||||
wnmsleep_ie = (struct wnm_sleep_element *) pos;
|
||||
else if (*pos == WLAN_EID_TFS_REQ) {
|
||||
if (!tfsreq_ie_start)
|
||||
@ -251,20 +259,14 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
|
||||
static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
|
||||
const u8 *addr,
|
||||
u8 dialog_token,
|
||||
const char *url)
|
||||
u8 dialog_token)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
size_t url_len, len;
|
||||
size_t 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));
|
||||
mgmt = os_zalloc(sizeof(*mgmt));
|
||||
if (mgmt == NULL)
|
||||
return -1;
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
@ -279,11 +281,6 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
|
||||
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 "
|
||||
@ -307,6 +304,20 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
|
||||
{
|
||||
u8 dialog_token, reason;
|
||||
const u8 *pos, *end;
|
||||
int enabled = hapd->conf->bss_transition;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled)
|
||||
enabled = 1;
|
||||
#endif /* CONFIG_MBO */
|
||||
if (!enabled) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore BSS Transition Management Query from "
|
||||
MACSTR
|
||||
" since BSS Transition Management is disabled",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
|
||||
@ -326,7 +337,20 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
|
||||
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);
|
||||
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
if (sta->agreed_to_steer) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->agreed_to_steer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -336,6 +360,21 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
|
||||
{
|
||||
u8 dialog_token, status_code, bss_termination_delay;
|
||||
const u8 *pos, *end;
|
||||
int enabled = hapd->conf->bss_transition;
|
||||
struct sta_info *sta;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled)
|
||||
enabled = 1;
|
||||
#endif /* CONFIG_MBO */
|
||||
if (!enabled) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore BSS Transition Management Response from "
|
||||
MACSTR
|
||||
" since BSS Transition Management is disabled",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < 3) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
|
||||
@ -354,11 +393,23 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
|
||||
"bss_termination_delay=%u", MAC2STR(addr), dialog_token,
|
||||
status_code, bss_termination_delay);
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for received BSS TM Response",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
sta->agreed_to_steer = 1;
|
||||
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
|
||||
eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
|
||||
hapd, sta);
|
||||
wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
|
||||
MAC2STR(pos));
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
|
||||
@ -368,6 +419,7 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
|
||||
MAC2STR(pos));
|
||||
pos += ETH_ALEN;
|
||||
} else {
|
||||
sta->agreed_to_steer = 0;
|
||||
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);
|
||||
@ -401,6 +453,48 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
u8 dialog_token;
|
||||
char *hex;
|
||||
size_t hex_len;
|
||||
|
||||
if (!hapd->conf->coloc_intf_reporting) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Ignore unexpected Collocated Interference Report from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Ignore too short Collocated Interference Report from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
dialog_token = *buf++;
|
||||
len--;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Received Collocated Interference Report frame from "
|
||||
MACSTR " (dialog_token=%u)",
|
||||
MAC2STR(addr), dialog_token);
|
||||
wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
|
||||
buf, len);
|
||||
|
||||
hex_len = 2 * len + 1;
|
||||
hex = os_malloc(hex_len);
|
||||
if (!hex)
|
||||
return;
|
||||
wpa_snprintf_hex(hex, hex_len, buf, len);
|
||||
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
|
||||
MAC2STR(addr), dialog_token, hex);
|
||||
os_free(hex);
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
@ -431,6 +525,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
case WNM_COLLOCATED_INTERFERENCE_REPORT:
|
||||
ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
|
||||
@ -629,3 +727,40 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
unsigned int auto_report, unsigned int timeout)
|
||||
{
|
||||
u8 buf[100], *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 dialog_token = 1;
|
||||
|
||||
if (auto_report > 3 || timeout > 63)
|
||||
return -1;
|
||||
os_memset(buf, 0, sizeof(buf));
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, 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.coloc_intf_req.action =
|
||||
WNM_COLLOCATED_INTERFERENCE_REQ;
|
||||
mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
|
||||
mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
|
||||
pos = &mgmt->u.action.u.coloc_intf_req.req_info;
|
||||
pos++;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
|
||||
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
|
||||
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
|
||||
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Failed to send Collocated Interference Request frame");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,5 +23,8 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *bss_term_dur, const char *url,
|
||||
const u8 *nei_rep, size_t nei_rep_len,
|
||||
const u8 *mbo_attrs, size_t mbo_len);
|
||||
void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
unsigned int auto_report, unsigned int timeout);
|
||||
|
||||
#endif /* WNM_AP_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
|
||||
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -14,6 +14,8 @@
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
struct vlan_description;
|
||||
|
||||
#define MAX_OWN_IE_OVERRIDE 256
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -37,73 +39,99 @@ struct ft_rrb_frame {
|
||||
|
||||
#define FT_PACKET_REQUEST 0
|
||||
#define FT_PACKET_RESPONSE 1
|
||||
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
|
||||
#define FT_PACKET_R0KH_R1KH_PULL 200
|
||||
#define FT_PACKET_R0KH_R1KH_RESP 201
|
||||
#define FT_PACKET_R0KH_R1KH_PUSH 202
|
||||
|
||||
#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
|
||||
#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
||||
WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \
|
||||
ETH_ALEN)
|
||||
#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
|
||||
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r. These
|
||||
* use OUI Extended EtherType as the encapsulating format. */
|
||||
#define FT_PACKET_R0KH_R1KH_PULL 0x01
|
||||
#define FT_PACKET_R0KH_R1KH_RESP 0x02
|
||||
#define FT_PACKET_R0KH_R1KH_PUSH 0x03
|
||||
#define FT_PACKET_R0KH_R1KH_SEQ_REQ 0x04
|
||||
#define FT_PACKET_R0KH_R1KH_SEQ_RESP 0x05
|
||||
|
||||
struct ft_r0kh_r1kh_pull_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
|
||||
le16 data_length; /* little endian length of data (44) */
|
||||
u8 ap_address[ETH_ALEN];
|
||||
/* packet layout
|
||||
* IEEE 802 extended OUI ethertype frame header
|
||||
* u16 authlen (little endian)
|
||||
* multiple of struct ft_rrb_tlv (authenticated only, length = authlen)
|
||||
* multiple of struct ft_rrb_tlv (AES-SIV encrypted, AES-SIV needs an extra
|
||||
* blocksize length)
|
||||
*
|
||||
* AES-SIV AAD;
|
||||
* source MAC address (6)
|
||||
* authenticated-only TLVs (authlen)
|
||||
* subtype (1; FT_PACKET_*)
|
||||
*/
|
||||
|
||||
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];
|
||||
u8 pad[FT_R0KH_R1KH_PULL_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
#define FT_RRB_NONCE_LEN 16
|
||||
|
||||
#define FT_RRB_LAST_EMPTY 0 /* placeholder or padding */
|
||||
|
||||
#define FT_RRB_SEQ 1 /* struct ft_rrb_seq */
|
||||
#define FT_RRB_NONCE 2 /* size FT_RRB_NONCE_LEN */
|
||||
#define FT_RRB_TIMESTAMP 3 /* le32 unix seconds */
|
||||
|
||||
#define FT_RRB_R0KH_ID 4 /* FT_R0KH_ID_MAX_LEN */
|
||||
#define FT_RRB_R1KH_ID 5 /* FT_R1KH_ID_LEN */
|
||||
#define FT_RRB_S1KH_ID 6 /* ETH_ALEN */
|
||||
|
||||
#define FT_RRB_PMK_R0_NAME 7 /* WPA_PMK_NAME_LEN */
|
||||
#define FT_RRB_PMK_R0 8 /* PMK_LEN */
|
||||
#define FT_RRB_PMK_R1_NAME 9 /* WPA_PMK_NAME_LEN */
|
||||
#define FT_RRB_PMK_R1 10 /* PMK_LEN */
|
||||
|
||||
#define FT_RRB_PAIRWISE 11 /* le16 */
|
||||
#define FT_RRB_EXPIRES_IN 12 /* le16 seconds */
|
||||
|
||||
#define FT_RRB_VLAN_UNTAGGED 13 /* le16 */
|
||||
#define FT_RRB_VLAN_TAGGED 14 /* n times le16 */
|
||||
|
||||
#define FT_RRB_IDENTITY 15
|
||||
#define FT_RRB_RADIUS_CUI 16
|
||||
#define FT_RRB_SESSION_TIMEOUT 17 /* le32 seconds */
|
||||
|
||||
struct ft_rrb_tlv {
|
||||
le16 type;
|
||||
le16 len;
|
||||
/* followed by data of length len */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
||||
FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \
|
||||
WPA_PMK_NAME_LEN + 2)
|
||||
#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
|
||||
struct ft_r0kh_r1kh_resp_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
|
||||
le16 data_length; /* little endian length of data (78) */
|
||||
u8 ap_address[ETH_ALEN];
|
||||
|
||||
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];
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
|
||||
le16 pairwise;
|
||||
u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
struct ft_rrb_seq {
|
||||
le32 dom;
|
||||
le32 seq;
|
||||
le32 ts;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \
|
||||
WPA_PMK_NAME_LEN + PMK_LEN + \
|
||||
WPA_PMK_NAME_LEN + 2)
|
||||
#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
|
||||
struct ft_r0kh_r1kh_push_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
|
||||
le16 data_length; /* little endian length of data (82) */
|
||||
u8 ap_address[ETH_ALEN];
|
||||
|
||||
/* Encrypted with AES key-wrap */
|
||||
u8 timestamp[4]; /* current time in seconds since unix epoch, little
|
||||
* endian */
|
||||
u8 r1kh_id[FT_R1KH_ID_LEN];
|
||||
u8 s1kh_id[ETH_ALEN];
|
||||
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
|
||||
u8 pmk_r1[PMK_LEN];
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
|
||||
le16 pairwise;
|
||||
u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
} STRUCT_PACKED;
|
||||
/* session TLVs:
|
||||
* required: PMK_R1, PMK_R1_NAME, PAIRWISE
|
||||
* optional: VLAN_UNTAGGED, VLAN_TAGGED, EXPIRES_IN, IDENTITY, RADIUS_CUI,
|
||||
* SESSION_TIMEOUT
|
||||
*
|
||||
* pull frame TLVs:
|
||||
* auth:
|
||||
* required: SEQ, NONCE, R0KH_ID, R1KH_ID
|
||||
* encrypted:
|
||||
* required: PMK_R0_NAME, S1KH_ID
|
||||
*
|
||||
* response frame TLVs:
|
||||
* auth:
|
||||
* required: SEQ, NONCE, R0KH_ID, R1KH_ID
|
||||
* encrypted:
|
||||
* required: S1KH_ID
|
||||
* optional: session TLVs
|
||||
*
|
||||
* push frame TLVs:
|
||||
* auth:
|
||||
* required: SEQ, R0KH_ID, R1KH_ID
|
||||
* encrypted:
|
||||
* required: S1KH_ID, PMK_R0_NAME, session TLVs
|
||||
*
|
||||
* sequence number request frame TLVs:
|
||||
* auth:
|
||||
* required: R0KH_ID, R1KH_ID, NONCE
|
||||
*
|
||||
* sequence number response frame TLVs:
|
||||
* auth:
|
||||
* required: SEQ, NONCE, R0KH_ID, R1KH_ID
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
@ -116,6 +144,7 @@ struct wpa_authenticator;
|
||||
struct wpa_state_machine;
|
||||
struct rsn_pmksa_cache_entry;
|
||||
struct eapol_state_machine;
|
||||
struct ft_remote_seq;
|
||||
|
||||
|
||||
struct ft_remote_r0kh {
|
||||
@ -123,7 +152,8 @@ struct ft_remote_r0kh {
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 id[FT_R0KH_ID_MAX_LEN];
|
||||
size_t id_len;
|
||||
u8 key[16];
|
||||
u8 key[32];
|
||||
struct ft_remote_seq *seq;
|
||||
};
|
||||
|
||||
|
||||
@ -131,7 +161,8 @@ struct ft_remote_r1kh {
|
||||
struct ft_remote_r1kh *next;
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 id[FT_R1KH_ID_LEN];
|
||||
u8 key[16];
|
||||
u8 key[32];
|
||||
struct ft_remote_seq *seq;
|
||||
};
|
||||
|
||||
|
||||
@ -144,10 +175,12 @@ struct wpa_auth_config {
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int wpa_ptk_rekey;
|
||||
u32 wpa_group_update_count;
|
||||
u32 wpa_pairwise_update_count;
|
||||
int wpa_disable_eapol_key_retries;
|
||||
int rsn_pairwise;
|
||||
int rsn_preauth;
|
||||
int eapol_version;
|
||||
int peerkey;
|
||||
int wmm_enabled;
|
||||
int wmm_uapsd;
|
||||
int disable_pmksa_caching;
|
||||
@ -156,21 +189,28 @@ struct wpa_auth_config {
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum mfp_options ieee80211w;
|
||||
int group_mgmt_cipher;
|
||||
int sae_require_mfp;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
|
||||
size_t r0_key_holder_len;
|
||||
u8 r1_key_holder[FT_R1KH_ID_LEN];
|
||||
u32 r0_key_lifetime;
|
||||
u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
|
||||
int rkh_pos_timeout;
|
||||
int rkh_neg_timeout;
|
||||
int rkh_pull_timeout; /* ms */
|
||||
int rkh_pull_retries;
|
||||
int r1_max_key_lifetime;
|
||||
u32 reassociation_deadline;
|
||||
struct ft_remote_r0kh *r0kh_list;
|
||||
struct ft_remote_r1kh *r1kh_list;
|
||||
struct ft_remote_r0kh **r0kh_list;
|
||||
struct ft_remote_r1kh **r1kh_list;
|
||||
int pmk_r1_push;
|
||||
int ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int ft_psk_generate_local;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
int disable_gtk;
|
||||
int ap_mlme;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
@ -184,6 +224,10 @@ struct wpa_auth_config {
|
||||
u8 ip_addr_start[4];
|
||||
u8 ip_addr_end[4];
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_FILS
|
||||
unsigned int fils_cache_id_set:1;
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
#endif /* CONFIG_FILS */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -197,7 +241,6 @@ typedef enum {
|
||||
} wpa_eapol_variable;
|
||||
|
||||
struct wpa_auth_callbacks {
|
||||
void *ctx;
|
||||
void (*logger)(void *ctx, const u8 *addr, logger_level level,
|
||||
const char *txt);
|
||||
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
|
||||
@ -207,7 +250,7 @@ struct wpa_auth_callbacks {
|
||||
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 *p2p_dev_addr,
|
||||
const u8 *prev_psk);
|
||||
const u8 *prev_psk, size_t *psk_len);
|
||||
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);
|
||||
@ -220,13 +263,29 @@ struct wpa_auth_callbacks {
|
||||
void *ctx), void *cb_ctx);
|
||||
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
|
||||
size_t data_len);
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
|
||||
size_t data_len);
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||
int (*set_vlan)(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan);
|
||||
int (*get_vlan)(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan);
|
||||
int (*set_identity)(void *ctx, const u8 *sta_addr,
|
||||
const u8 *identity, size_t identity_len);
|
||||
size_t (*get_identity)(void *ctx, const u8 *sta_addr, const u8 **buf);
|
||||
int (*set_radius_cui)(void *ctx, const u8 *sta_addr,
|
||||
const u8 *radius_cui, size_t radius_cui_len);
|
||||
size_t (*get_radius_cui)(void *ctx, const u8 *sta_addr, const u8 **buf);
|
||||
void (*set_session_timeout)(void *ctx, const u8 *sta_addr,
|
||||
int session_timeout);
|
||||
int (*get_session_timeout)(void *ctx, const u8 *sta_addr);
|
||||
|
||||
int (*send_ft_action)(void *ctx, const u8 *dst,
|
||||
const u8 *data, size_t data_len);
|
||||
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
|
||||
size_t tspec_ielen);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_MESH
|
||||
int (*start_ampe)(void *ctx, const u8 *sta_addr);
|
||||
#endif /* CONFIG_MESH */
|
||||
@ -234,7 +293,8 @@ struct wpa_auth_callbacks {
|
||||
|
||||
struct wpa_authenticator * wpa_init(const u8 *addr,
|
||||
struct wpa_auth_config *conf,
|
||||
struct wpa_auth_callbacks *cb);
|
||||
const struct wpa_auth_callbacks *cb,
|
||||
void *cb_ctx);
|
||||
int wpa_init_keys(struct wpa_authenticator *wpa_auth);
|
||||
void wpa_deinit(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
|
||||
@ -244,13 +304,14 @@ enum {
|
||||
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
|
||||
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
|
||||
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
|
||||
WPA_INVALID_MDIE, WPA_INVALID_PROTO
|
||||
WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
const u8 *osen_ie, size_t osen_ie_len);
|
||||
@ -267,7 +328,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
||||
u8 *data, size_t data_len);
|
||||
enum wpa_event {
|
||||
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
|
||||
WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
|
||||
WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_ASSOC_FILS, WPA_DRV_STA_REMOVED
|
||||
};
|
||||
void wpa_remove_ptk(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
|
||||
@ -281,6 +342,7 @@ int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
@ -297,13 +359,28 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
struct eapol_state_machine *eapol);
|
||||
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, const u8 *pmkid);
|
||||
void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
|
||||
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
int session_timeout, int akmp);
|
||||
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr);
|
||||
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
|
||||
size_t len);
|
||||
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
char *buf, size_t len);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
|
||||
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
|
||||
const u8 *pmkid, int expiration);
|
||||
int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
|
||||
const u8 *pmkid);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr, const u8 *pmkid);
|
||||
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_authenticator *wpa_auth,
|
||||
@ -312,7 +389,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
|
||||
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int ack);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
size_t max_len, int auth_alg,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
@ -327,8 +404,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
|
||||
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
const u8 *data, size_t data_len);
|
||||
void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix, const u8 *data,
|
||||
size_t data_len);
|
||||
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
|
||||
void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
|
||||
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
|
||||
@ -347,5 +429,44 @@ void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
|
||||
|
||||
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
size_t pmk_len, const u8 *snonce, const u8 *anonce,
|
||||
const u8 *dhss, size_t dhss_len,
|
||||
struct wpabuf *g_sta, struct wpabuf *g_ap);
|
||||
int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
|
||||
const struct ieee80211_mgmt *mgmt, size_t frame_len,
|
||||
u8 *pos, size_t left);
|
||||
int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
|
||||
size_t current_len, size_t max_len,
|
||||
const struct wpabuf *hlp);
|
||||
int fils_set_tk(struct wpa_state_machine *sm);
|
||||
u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *eid,
|
||||
const u8 *fils_session,
|
||||
struct wpabuf *fils_hlp_resp);
|
||||
const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
|
||||
const u8 *ies, size_t ies_len,
|
||||
const u8 *fils_session);
|
||||
int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
|
||||
size_t ies_len);
|
||||
|
||||
int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
|
||||
u8 *buf, size_t len);
|
||||
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
|
||||
u8 *fils_anonce, u8 *fils_snonce,
|
||||
u8 *fils_kek, size_t *fils_kek_len);
|
||||
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
|
||||
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
void *ctx1, void *ctx2);
|
||||
int wpa_auth_resend_m3(struct wpa_state_machine *sm,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
void *ctx1, void *ctx2);
|
||||
int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
void *ctx1, void *ctx2);
|
||||
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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/sae.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
@ -17,6 +19,7 @@
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "eth_p_oui.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "preauth_auth.h"
|
||||
@ -24,6 +27,7 @@
|
||||
#include "tkip_countermeasures.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "pmksa_cache_auth.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
|
||||
@ -41,10 +45,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
|
||||
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
|
||||
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
|
||||
wconf->wpa_group_update_count = conf->wpa_group_update_count;
|
||||
wconf->wpa_disable_eapol_key_retries =
|
||||
conf->wpa_disable_eapol_key_retries;
|
||||
wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
|
||||
wconf->rsn_pairwise = conf->rsn_pairwise;
|
||||
wconf->rsn_preauth = conf->rsn_preauth;
|
||||
wconf->eapol_version = conf->eapol_version;
|
||||
wconf->peerkey = conf->peerkey;
|
||||
wconf->wmm_enabled = conf->wmm_enabled;
|
||||
wconf->wmm_uapsd = conf->wmm_uapsd;
|
||||
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
|
||||
@ -52,8 +59,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
wconf->ieee80211w = conf->ieee80211w;
|
||||
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
|
||||
wconf->sae_require_mfp = conf->sae_require_mfp;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
wconf->ssid_len = conf->ssid.ssid_len;
|
||||
if (wconf->ssid_len > SSID_MAX_LEN)
|
||||
wconf->ssid_len = SSID_MAX_LEN;
|
||||
@ -68,12 +76,18 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
}
|
||||
os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
|
||||
wconf->r0_key_lifetime = conf->r0_key_lifetime;
|
||||
wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime;
|
||||
wconf->reassociation_deadline = conf->reassociation_deadline;
|
||||
wconf->r0kh_list = conf->r0kh_list;
|
||||
wconf->r1kh_list = conf->r1kh_list;
|
||||
wconf->rkh_pos_timeout = conf->rkh_pos_timeout;
|
||||
wconf->rkh_neg_timeout = conf->rkh_neg_timeout;
|
||||
wconf->rkh_pull_timeout = conf->rkh_pull_timeout;
|
||||
wconf->rkh_pull_retries = conf->rkh_pull_retries;
|
||||
wconf->r0kh_list = &conf->r0kh_list;
|
||||
wconf->r1kh_list = &conf->r1kh_list;
|
||||
wconf->pmk_r1_push = conf->pmk_r1_push;
|
||||
wconf->ft_over_ds = conf->ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
wconf->ft_psk_generate_local = conf->ft_psk_generate_local;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_HS20
|
||||
wconf->disable_gtk = conf->disable_dgaf;
|
||||
if (conf->osen) {
|
||||
@ -107,6 +121,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
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 */
|
||||
#ifdef CONFIG_FILS
|
||||
wconf->fils_cache_id_set = conf->fils_cache_id_set;
|
||||
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
|
||||
FILS_CACHE_ID_LEN);
|
||||
#endif /* CONFIG_FILS */
|
||||
}
|
||||
|
||||
|
||||
@ -223,20 +242,47 @@ 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)
|
||||
const u8 *prev_psk, size_t *psk_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
const u8 *psk;
|
||||
|
||||
if (psk_len)
|
||||
*psk_len = PMK_LEN;
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
|
||||
if (!sta->sae || prev_psk)
|
||||
return NULL;
|
||||
return sta->sae->pmk;
|
||||
}
|
||||
if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No PSK for STA trying to use SAE with PMKSA caching");
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
|
||||
sta && sta->owe_pmk) {
|
||||
if (psk_len)
|
||||
*psk_len = sta->owe_pmk_len;
|
||||
return sta->owe_pmk;
|
||||
}
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) {
|
||||
struct rsn_pmksa_cache_entry *sa;
|
||||
|
||||
sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
|
||||
if (sa && sa->akmp == WPA_KEY_MGMT_OWE) {
|
||||
if (psk_len)
|
||||
*psk_len = sa->pmk_len;
|
||||
return sa->pmk;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
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
|
||||
@ -307,6 +353,37 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta) {
|
||||
sta->last_tk_alg = alg;
|
||||
sta->last_tk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(sta->last_tk, key, key_len);
|
||||
sta->last_tk_len = key_len;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
} else if (alg == WPA_ALG_IGTK ||
|
||||
alg == WPA_ALG_BIP_GMAC_128 ||
|
||||
alg == WPA_ALG_BIP_GMAC_256 ||
|
||||
alg == WPA_ALG_BIP_CMAC_256) {
|
||||
hapd->last_igtk_alg = alg;
|
||||
hapd->last_igtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_igtk, key, key_len);
|
||||
hapd->last_igtk_len = key_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
} else {
|
||||
hapd->last_gtk_alg = alg;
|
||||
hapd->last_gtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_gtk, key, key_len);
|
||||
hapd->last_gtk_len = key_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
|
||||
key, key_len);
|
||||
}
|
||||
@ -401,7 +478,32 @@ static int hostapd_wpa_auth_for_each_auth(
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
struct wpa_ft_rrb_rx_later_data {
|
||||
struct dl_list list;
|
||||
u8 addr[ETH_ALEN];
|
||||
size_t data_len;
|
||||
/* followed by data_len octets of data */
|
||||
};
|
||||
|
||||
static void hostapd_wpa_ft_rrb_rx_later(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct wpa_ft_rrb_rx_later_data *data, *n;
|
||||
|
||||
dl_list_for_each_safe(data, n, &hapd->l2_queue,
|
||||
struct wpa_ft_rrb_rx_later_data, list) {
|
||||
if (hapd->wpa_auth) {
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth, data->addr,
|
||||
(const u8 *) (data + 1),
|
||||
data->data_len);
|
||||
}
|
||||
dl_list_del(&data->list);
|
||||
os_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct wpa_auth_ft_iface_iter_data {
|
||||
struct hostapd_data *src_hapd;
|
||||
@ -414,33 +516,54 @@ struct wpa_auth_ft_iface_iter_data {
|
||||
static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct wpa_auth_ft_iface_iter_data *idata = ctx;
|
||||
struct wpa_ft_rrb_rx_later_data *data;
|
||||
struct hostapd_data *hapd;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
if (hapd == idata->src_hapd)
|
||||
if (hapd == idata->src_hapd ||
|
||||
!hapd->wpa_auth ||
|
||||
os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0)
|
||||
continue;
|
||||
if (!hapd->wpa_auth)
|
||||
continue;
|
||||
if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
|
||||
"locally managed BSS " MACSTR "@%s -> "
|
||||
MACSTR "@%s",
|
||||
MAC2STR(idata->src_hapd->own_addr),
|
||||
idata->src_hapd->conf->iface,
|
||||
MAC2STR(hapd->own_addr), hapd->conf->iface);
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth,
|
||||
idata->src_hapd->own_addr,
|
||||
idata->data, idata->data_len);
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Send RRB data directly to locally managed BSS "
|
||||
MACSTR "@%s -> " MACSTR "@%s",
|
||||
MAC2STR(idata->src_hapd->own_addr),
|
||||
idata->src_hapd->conf->iface,
|
||||
MAC2STR(hapd->own_addr), hapd->conf->iface);
|
||||
|
||||
/* Defer wpa_ft_rrb_rx() until next eloop step as this is
|
||||
* when it would be triggered when reading from a socket.
|
||||
* This avoids
|
||||
* hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv,
|
||||
* that is calling hapd0:recv handler from within
|
||||
* hapd0:send directly.
|
||||
*/
|
||||
data = os_zalloc(sizeof(*data) + idata->data_len);
|
||||
if (!data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
os_memcpy(data->addr, idata->src_hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(data + 1, idata->data, idata->data_len);
|
||||
data->data_len = idata->data_len;
|
||||
|
||||
dl_list_add(&hapd->l2_queue, &data->list);
|
||||
|
||||
if (!eloop_is_timeout_registered(hostapd_wpa_ft_rrb_rx_later,
|
||||
hapd, NULL))
|
||||
eloop_register_timeout(0, 0,
|
||||
hostapd_wpa_ft_rrb_rx_later,
|
||||
hapd, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
||||
@ -465,7 +588,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->for_each_interface) {
|
||||
int res;
|
||||
@ -480,7 +603,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
||||
if (res == 1)
|
||||
return data_len;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
if (hapd->driver && hapd->driver->send_ether)
|
||||
return hapd->driver->send_ether(hapd->drv_priv, dst,
|
||||
@ -503,7 +626,157 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
static struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd,
|
||||
u8 oui_suffix)
|
||||
{
|
||||
switch (oui_suffix) {
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
case FT_PACKET_R0KH_R1KH_PULL:
|
||||
return hapd->oui_pull;
|
||||
case FT_PACKET_R0KH_R1KH_RESP:
|
||||
return hapd->oui_resp;
|
||||
case FT_PACKET_R0KH_R1KH_PUSH:
|
||||
return hapd->oui_push;
|
||||
case FT_PACKET_R0KH_R1KH_SEQ_REQ:
|
||||
return hapd->oui_sreq;
|
||||
case FT_PACKET_R0KH_R1KH_SEQ_RESP:
|
||||
return hapd->oui_sresp;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
struct oui_deliver_later_data {
|
||||
struct dl_list list;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
size_t data_len;
|
||||
u8 oui_suffix;
|
||||
/* followed by data_len octets of data */
|
||||
};
|
||||
|
||||
static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct oui_deliver_later_data *data, *n;
|
||||
struct eth_p_oui_ctx *oui_ctx;
|
||||
|
||||
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
|
||||
struct oui_deliver_later_data, list) {
|
||||
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
|
||||
if (hapd->wpa_auth && oui_ctx) {
|
||||
eth_p_oui_deliver(oui_ctx, data->src_addr,
|
||||
data->dst_addr,
|
||||
(const u8 *) (data + 1),
|
||||
data->data_len);
|
||||
}
|
||||
dl_list_del(&data->list);
|
||||
os_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct wpa_auth_oui_iface_iter_data {
|
||||
struct hostapd_data *src_hapd;
|
||||
const u8 *dst_addr;
|
||||
const u8 *data;
|
||||
size_t data_len;
|
||||
u8 oui_suffix;
|
||||
};
|
||||
|
||||
static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct wpa_auth_oui_iface_iter_data *idata = ctx;
|
||||
struct oui_deliver_later_data *data;
|
||||
struct hostapd_data *hapd;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
if (hapd == idata->src_hapd)
|
||||
continue;
|
||||
if (!is_multicast_ether_addr(idata->dst_addr) &&
|
||||
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
|
||||
continue;
|
||||
|
||||
/* defer eth_p_oui_deliver until next eloop step as this is
|
||||
* when it would be triggerd from reading from sock
|
||||
* This avoids
|
||||
* hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv,
|
||||
* that is calling hapd0:recv handler from within
|
||||
* hapd0:send directly.
|
||||
*/
|
||||
data = os_zalloc(sizeof(*data) + idata->data_len);
|
||||
if (!data)
|
||||
return 1;
|
||||
|
||||
os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
|
||||
os_memcpy(data + 1, idata->data, idata->data_len);
|
||||
data->data_len = idata->data_len;
|
||||
data->oui_suffix = idata->oui_suffix;
|
||||
|
||||
dl_list_add(&hapd->l2_oui_queue, &data->list);
|
||||
|
||||
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
|
||||
hapd, NULL))
|
||||
eloop_register_timeout(0, 0,
|
||||
hostapd_oui_deliver_later,
|
||||
hapd, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct eth_p_oui_ctx *oui_ctx;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->for_each_interface) {
|
||||
struct wpa_auth_oui_iface_iter_data idata;
|
||||
int res;
|
||||
|
||||
idata.src_hapd = hapd;
|
||||
idata.dst_addr = dst;
|
||||
idata.data = data;
|
||||
idata.data_len = data_len;
|
||||
idata.oui_suffix = oui_suffix;
|
||||
res = hapd->iface->interfaces->for_each_interface(
|
||||
hapd->iface->interfaces, hostapd_wpa_auth_oui_iter,
|
||||
&idata);
|
||||
if (res == 1)
|
||||
return data_len;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix);
|
||||
if (!oui_ctx)
|
||||
return -1;
|
||||
|
||||
return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len);
|
||||
#else /* CONFIG_ETH_P_OUI */
|
||||
return -1;
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
|
||||
const u8 *data, size_t data_len)
|
||||
@ -563,6 +836,244 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta || !sta->wpa_sm)
|
||||
return -1;
|
||||
|
||||
if (vlan->notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from FT",
|
||||
vlan->untagged, vlan->tagged[0] ? "+" : "");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
|
||||
return -1;
|
||||
/* Configure wpa_group for GTK but ignore error due to driver not
|
||||
* knowing this STA. */
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
|
||||
if (sta->vlan_id)
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
if (sta->vlan_desc)
|
||||
*vlan = *sta->vlan_desc;
|
||||
else
|
||||
os_memset(vlan, 0, sizeof(*vlan));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr,
|
||||
const u8 *identity, size_t identity_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
os_free(sta->identity);
|
||||
sta->identity = NULL;
|
||||
|
||||
if (sta->eapol_sm) {
|
||||
os_free(sta->eapol_sm->identity);
|
||||
sta->eapol_sm->identity = NULL;
|
||||
sta->eapol_sm->identity_len = 0;
|
||||
}
|
||||
|
||||
if (!identity_len)
|
||||
return 0;
|
||||
|
||||
/* sta->identity is NULL terminated */
|
||||
sta->identity = os_zalloc(identity_len + 1);
|
||||
if (!sta->identity)
|
||||
return -1;
|
||||
os_memcpy(sta->identity, identity, identity_len);
|
||||
|
||||
if (sta->eapol_sm) {
|
||||
sta->eapol_sm->identity = os_zalloc(identity_len);
|
||||
if (!sta->eapol_sm->identity)
|
||||
return -1;
|
||||
os_memcpy(sta->eapol_sm->identity, identity, identity_len);
|
||||
sta->eapol_sm->identity_len = identity_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
hostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
size_t len;
|
||||
char *identity;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return 0;
|
||||
|
||||
*buf = ieee802_1x_get_identity(sta->eapol_sm, &len);
|
||||
if (*buf && len)
|
||||
return len;
|
||||
|
||||
if (!sta->identity) {
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
identity = sta->identity;
|
||||
len = os_strlen(identity);
|
||||
*buf = (u8 *) identity;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr,
|
||||
const u8 *radius_cui, size_t radius_cui_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
os_free(sta->radius_cui);
|
||||
sta->radius_cui = NULL;
|
||||
|
||||
if (sta->eapol_sm) {
|
||||
wpabuf_free(sta->eapol_sm->radius_cui);
|
||||
sta->eapol_sm->radius_cui = NULL;
|
||||
}
|
||||
|
||||
if (!radius_cui)
|
||||
return 0;
|
||||
|
||||
/* sta->radius_cui is NULL terminated */
|
||||
sta->radius_cui = os_zalloc(radius_cui_len + 1);
|
||||
if (!sta->radius_cui)
|
||||
return -1;
|
||||
os_memcpy(sta->radius_cui, radius_cui, radius_cui_len);
|
||||
|
||||
if (sta->eapol_sm) {
|
||||
sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui,
|
||||
radius_cui_len);
|
||||
if (!sta->eapol_sm->radius_cui)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
hostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
struct wpabuf *b;
|
||||
size_t len;
|
||||
char *radius_cui;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return 0;
|
||||
|
||||
b = ieee802_1x_get_radius_cui(sta->eapol_sm);
|
||||
if (b) {
|
||||
len = wpabuf_len(b);
|
||||
*buf = wpabuf_head(b);
|
||||
return len;
|
||||
}
|
||||
|
||||
if (!sta->radius_cui) {
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
radius_cui = sta->radius_cui;
|
||||
len = os_strlen(radius_cui);
|
||||
*buf = (u8 *) radius_cui;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr,
|
||||
int session_timeout)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
if (session_timeout) {
|
||||
os_get_reltime(&sta->session_timeout);
|
||||
sta->session_timeout.sec += session_timeout;
|
||||
sta->session_timeout_set = 1;
|
||||
ap_sta_session_timeout(hapd, sta, session_timeout);
|
||||
} else {
|
||||
sta->session_timeout_set = 0;
|
||||
ap_sta_no_session_timeout(hapd, sta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
struct os_reltime now, remaining;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta || !sta->session_timeout_set)
|
||||
return 0;
|
||||
|
||||
os_get_reltime(&now);
|
||||
if (os_reltime_before(&sta->session_timeout, &now)) {
|
||||
/* already expired, return >0 as timeout was set */
|
||||
return 1;
|
||||
}
|
||||
|
||||
os_reltime_sub(&sta->session_timeout, &now, &remaining);
|
||||
|
||||
return (remaining.sec > 0) ? remaining.sec : 1;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
@ -581,6 +1092,22 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||
MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr));
|
||||
if (!is_multicast_ether_addr(dst_addr) &&
|
||||
os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0)
|
||||
return;
|
||||
wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf,
|
||||
len);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
||||
u8 *tspec_ie, size_t tspec_ielen)
|
||||
{
|
||||
@ -588,13 +1115,94 @@ static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
||||
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
static int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd,
|
||||
const char *ft_iface)
|
||||
{
|
||||
hapd->oui_pull = eth_p_oui_register(hapd, ft_iface,
|
||||
FT_PACKET_R0KH_R1KH_PULL,
|
||||
hostapd_rrb_oui_receive, hapd);
|
||||
if (!hapd->oui_pull)
|
||||
return -1;
|
||||
|
||||
hapd->oui_resp = eth_p_oui_register(hapd, ft_iface,
|
||||
FT_PACKET_R0KH_R1KH_RESP,
|
||||
hostapd_rrb_oui_receive, hapd);
|
||||
if (!hapd->oui_resp)
|
||||
return -1;
|
||||
|
||||
hapd->oui_push = eth_p_oui_register(hapd, ft_iface,
|
||||
FT_PACKET_R0KH_R1KH_PUSH,
|
||||
hostapd_rrb_oui_receive, hapd);
|
||||
if (!hapd->oui_push)
|
||||
return -1;
|
||||
|
||||
hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface,
|
||||
FT_PACKET_R0KH_R1KH_SEQ_REQ,
|
||||
hostapd_rrb_oui_receive, hapd);
|
||||
if (!hapd->oui_sreq)
|
||||
return -1;
|
||||
|
||||
hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface,
|
||||
FT_PACKET_R0KH_R1KH_SEQ_RESP,
|
||||
hostapd_rrb_oui_receive, hapd);
|
||||
if (!hapd->oui_sresp)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
|
||||
{
|
||||
eth_p_oui_unregister(hapd->oui_pull);
|
||||
hapd->oui_pull = NULL;
|
||||
eth_p_oui_unregister(hapd->oui_resp);
|
||||
hapd->oui_resp = NULL;
|
||||
eth_p_oui_unregister(hapd->oui_push);
|
||||
hapd->oui_push = NULL;
|
||||
eth_p_oui_unregister(hapd->oui_sreq);
|
||||
hapd->oui_sreq = NULL;
|
||||
eth_p_oui_unregister(hapd->oui_sresp);
|
||||
hapd->oui_sresp = NULL;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpa_auth_config _conf;
|
||||
struct wpa_auth_callbacks cb;
|
||||
static const struct wpa_auth_callbacks cb = {
|
||||
.logger = hostapd_wpa_auth_logger,
|
||||
.disconnect = hostapd_wpa_auth_disconnect,
|
||||
.mic_failure_report = hostapd_wpa_auth_mic_failure_report,
|
||||
.psk_failure_report = hostapd_wpa_auth_psk_failure_report,
|
||||
.set_eapol = hostapd_wpa_auth_set_eapol,
|
||||
.get_eapol = hostapd_wpa_auth_get_eapol,
|
||||
.get_psk = hostapd_wpa_auth_get_psk,
|
||||
.get_msk = hostapd_wpa_auth_get_msk,
|
||||
.set_key = hostapd_wpa_auth_set_key,
|
||||
.get_seqnum = hostapd_wpa_auth_get_seqnum,
|
||||
.send_eapol = hostapd_wpa_auth_send_eapol,
|
||||
.for_each_sta = hostapd_wpa_auth_for_each_sta,
|
||||
.for_each_auth = hostapd_wpa_auth_for_each_auth,
|
||||
.send_ether = hostapd_wpa_auth_send_ether,
|
||||
.send_oui = hostapd_wpa_auth_send_oui,
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
.send_ft_action = hostapd_wpa_auth_send_ft_action,
|
||||
.add_sta = hostapd_wpa_auth_add_sta,
|
||||
.add_tspec = hostapd_wpa_auth_add_tspec,
|
||||
.set_vlan = hostapd_wpa_auth_set_vlan,
|
||||
.get_vlan = hostapd_wpa_auth_get_vlan,
|
||||
.set_identity = hostapd_wpa_auth_set_identity,
|
||||
.get_identity = hostapd_wpa_auth_get_identity,
|
||||
.set_radius_cui = hostapd_wpa_auth_set_radius_cui,
|
||||
.get_radius_cui = hostapd_wpa_auth_get_radius_cui,
|
||||
.set_session_timeout = hostapd_wpa_auth_set_session_timeout,
|
||||
.get_session_timeout = hostapd_wpa_auth_get_session_timeout,
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
};
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
|
||||
@ -603,28 +1211,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
_conf.tx_status = 1;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
|
||||
_conf.ap_mlme = 1;
|
||||
os_memset(&cb, 0, sizeof(cb));
|
||||
cb.ctx = hapd;
|
||||
cb.logger = hostapd_wpa_auth_logger;
|
||||
cb.disconnect = hostapd_wpa_auth_disconnect;
|
||||
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
|
||||
cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
|
||||
cb.set_eapol = hostapd_wpa_auth_set_eapol;
|
||||
cb.get_eapol = hostapd_wpa_auth_get_eapol;
|
||||
cb.get_psk = hostapd_wpa_auth_get_psk;
|
||||
cb.get_msk = hostapd_wpa_auth_get_msk;
|
||||
cb.set_key = hostapd_wpa_auth_set_key;
|
||||
cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
|
||||
cb.send_eapol = hostapd_wpa_auth_send_eapol;
|
||||
cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
|
||||
cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
|
||||
cb.send_ether = hostapd_wpa_auth_send_ether;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
|
||||
cb.add_sta = hostapd_wpa_auth_add_sta;
|
||||
cb.add_tspec = hostapd_wpa_auth_add_tspec;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
|
||||
if (hapd->wpa_auth == NULL) {
|
||||
wpa_printf(MSG_ERROR, "WPA initialization failed.");
|
||||
return -1;
|
||||
@ -649,12 +1236,14 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (!hostapd_drv_none(hapd) &&
|
||||
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
||||
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
|
||||
hapd->conf->bridge :
|
||||
hapd->conf->iface, NULL, ETH_P_RRB,
|
||||
const char *ft_iface;
|
||||
|
||||
ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge :
|
||||
hapd->conf->iface;
|
||||
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
|
||||
hostapd_rrb_receive, hapd, 1);
|
||||
if (hapd->l2 == NULL &&
|
||||
(hapd->driver == NULL ||
|
||||
@ -663,8 +1252,14 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
"interface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to open ETH_P_OUI interface");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
return 0;
|
||||
|
||||
@ -702,8 +1297,13 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
|
||||
}
|
||||
ieee802_1x_deinit(hapd);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX);
|
||||
hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */
|
||||
eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX);
|
||||
hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */
|
||||
l2_packet_deinit(hapd->l2);
|
||||
hapd->l2 = NULL;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
hostapd_wpa_unregister_ft_oui(hapd);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
}
|
||||
|
@ -9,18 +9,13 @@
|
||||
#ifndef WPA_AUTH_I_H
|
||||
#define WPA_AUTH_I_H
|
||||
|
||||
#include "utils/list.h"
|
||||
|
||||
/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
|
||||
#define RSNA_MAX_EAPOL_RETRIES 4
|
||||
|
||||
struct wpa_group;
|
||||
|
||||
struct wpa_stsl_negotiation {
|
||||
struct wpa_stsl_negotiation *next;
|
||||
u8 initiator[ETH_ALEN];
|
||||
u8 peer[ETH_ALEN];
|
||||
};
|
||||
|
||||
|
||||
struct wpa_state_machine {
|
||||
struct wpa_authenticator *wpa_auth;
|
||||
struct wpa_group *group;
|
||||
@ -48,8 +43,9 @@ struct wpa_state_machine {
|
||||
Boolean AuthenticationRequest;
|
||||
Boolean ReAuthenticationRequest;
|
||||
Boolean Disconnect;
|
||||
int TimeoutCtr;
|
||||
int GTimeoutCtr;
|
||||
u16 disconnect_reason; /* specific reason code to use with Disconnect */
|
||||
u32 TimeoutCtr;
|
||||
u32 GTimeoutCtr;
|
||||
Boolean TimeoutEvt;
|
||||
Boolean EAPOLKeyReceived;
|
||||
Boolean EAPOLKeyPairwise;
|
||||
@ -62,6 +58,7 @@ struct wpa_state_machine {
|
||||
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
u8 PMK[PMK_LEN_MAX];
|
||||
unsigned int pmk_len;
|
||||
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
|
||||
struct wpa_ptk PTK;
|
||||
Boolean PTK_valid;
|
||||
Boolean pairwise_set;
|
||||
@ -89,11 +86,12 @@ struct wpa_state_machine {
|
||||
unsigned int rx_eapol_key_secure:1;
|
||||
unsigned int update_snonce:1;
|
||||
unsigned int alt_snonce_valid:1;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
unsigned int ft_completed:1;
|
||||
unsigned int pmk_r1_name_valid:1;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
unsigned int is_wnmsleep:1;
|
||||
unsigned int pmkid_set:1;
|
||||
|
||||
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
int req_replay_counter_used;
|
||||
@ -113,8 +111,9 @@ struct wpa_state_machine {
|
||||
u32 dot11RSNAStatsTKIPLocalMICFailures;
|
||||
u32 dot11RSNAStatsTKIPRemoteMICFailures;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
|
||||
* first 384 bits of MSK */
|
||||
size_t xxkey_len;
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
|
||||
* Request */
|
||||
@ -129,16 +128,30 @@ struct wpa_state_machine {
|
||||
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_pull_nonce[FT_RRB_NONCE_LEN];
|
||||
u8 ft_pending_auth_transaction;
|
||||
u8 ft_pending_current_ap[ETH_ALEN];
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int ft_pending_pull_left_retries;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
int pending_1_of_4_timeout;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
u8 ip_addr[4];
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
|
||||
u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
|
||||
size_t fils_key_auth_len;
|
||||
unsigned int fils_completed:1;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
void (*eapol_status_cb)(void *ctx1, void *ctx2);
|
||||
void *eapol_status_cb_ctx1;
|
||||
void *eapol_status_cb_ctx2;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
|
||||
@ -194,10 +207,9 @@ struct wpa_authenticator {
|
||||
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
|
||||
unsigned int dot11RSNA4WayHandshakeFailures;
|
||||
|
||||
struct wpa_stsl_negotiation *stsl_negotiations;
|
||||
|
||||
struct wpa_auth_config conf;
|
||||
struct wpa_auth_callbacks cb;
|
||||
const struct wpa_auth_callbacks *cb;
|
||||
void *cb_ctx;
|
||||
|
||||
u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
@ -213,6 +225,38 @@ struct wpa_authenticator {
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
#define FT_REMOTE_SEQ_BACKLOG 16
|
||||
struct ft_remote_seq_rx {
|
||||
u32 dom;
|
||||
struct os_reltime time_offset; /* local time - offset = remote time */
|
||||
|
||||
/* accepted sequence numbers: (offset ... offset + 0x40000000]
|
||||
* (except those in last)
|
||||
* dropped sequence numbers: (offset - 0x40000000 ... offset]
|
||||
* all others trigger SEQ_REQ message (except first message)
|
||||
*/
|
||||
u32 last[FT_REMOTE_SEQ_BACKLOG];
|
||||
unsigned int num_last;
|
||||
u32 offsetidx;
|
||||
|
||||
struct dl_list queue; /* send nonces + rrb msgs awaiting seq resp */
|
||||
};
|
||||
|
||||
struct ft_remote_seq_tx {
|
||||
u32 dom; /* non zero if initialized */
|
||||
u32 seq;
|
||||
};
|
||||
|
||||
struct ft_remote_seq {
|
||||
struct ft_remote_seq_rx rx;
|
||||
struct ft_remote_seq_tx tx;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
const u8 *pmkid);
|
||||
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
@ -231,24 +275,10 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
|
||||
int (*cb)(struct wpa_authenticator *a, void *ctx),
|
||||
void *cb_ctx);
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_stsl_negotiation *neg);
|
||||
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
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,
|
||||
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,
|
||||
const u8 *key_data, size_t key_data_len);
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
|
||||
int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
|
||||
size_t r0kh_id_len,
|
||||
int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *anonce, const u8 *snonce,
|
||||
u8 *buf, size_t len, const u8 *subelem,
|
||||
size_t subelem_len);
|
||||
@ -257,6 +287,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
|
||||
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
|
||||
const u8 *pmk_r0_name);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#endif /* WPA_AUTH_I_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - WPA/RSN IE and KDE definitions
|
||||
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -164,18 +164,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#ifdef CONFIG_SHA384
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_SHA384 */
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
|
||||
@ -210,6 +217,51 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#ifdef CONFIG_FILS
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_OWE
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
#ifdef CONFIG_DPP
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef CONFIG_HS20
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
|
||||
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
num_suites++;
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing) {
|
||||
@ -230,8 +282,6 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
capab = 0;
|
||||
if (conf->rsn_preauth)
|
||||
capab |= WPA_CAPABILITY_PREAUTH;
|
||||
if (conf->peerkey)
|
||||
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
|
||||
if (conf->wmm_enabled) {
|
||||
/* 4 PTKSA replay counters when using WMM */
|
||||
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
|
||||
@ -407,7 +457,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
|
||||
return res;
|
||||
pos += res;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
|
||||
res = wpa_write_mdie(&wpa_auth->conf, pos,
|
||||
buf + sizeof(buf) - pos);
|
||||
@ -415,7 +465,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
|
||||
return res;
|
||||
pos += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
|
||||
res = wpa_write_wpa_ie(&wpa_auth->conf,
|
||||
pos, buf + sizeof(buf) - pos);
|
||||
@ -474,7 +524,8 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
|
||||
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)
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
{
|
||||
struct wpa_ie_data data;
|
||||
int ciphers, key_mgmt, res, version;
|
||||
@ -509,12 +560,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
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
|
||||
#ifdef CONFIG_FILS
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
|
||||
selector = RSN_AUTH_KEY_MGMT_FILS_SHA384;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
|
||||
selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
#ifdef CONFIG_SHA384
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
|
||||
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
|
||||
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
|
||||
@ -531,6 +598,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
|
||||
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
|
||||
#ifdef CONFIG_OWE
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_OWE)
|
||||
selector = RSN_AUTH_KEY_MGMT_OWE;
|
||||
#endif /* CONFIG_OWE */
|
||||
#ifdef CONFIG_DPP
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
|
||||
selector = RSN_AUTH_KEY_MGMT_DPP;
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef CONFIG_HS20
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
|
||||
selector = RSN_AUTH_KEY_MGMT_OSEN;
|
||||
#endif /* CONFIG_HS20 */
|
||||
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
|
||||
|
||||
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
|
||||
@ -591,12 +670,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
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
|
||||
#ifdef CONFIG_FILS
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
|
||||
else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
#ifdef CONFIG_SHA384
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
|
||||
#endif /* CONFIG_SHA384 */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
|
||||
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
|
||||
@ -611,6 +706,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
#endif /* CONFIG_SAE */
|
||||
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
#ifdef CONFIG_OWE
|
||||
else if (key_mgmt & WPA_KEY_MGMT_OWE)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_OWE;
|
||||
#endif /* CONFIG_OWE */
|
||||
#ifdef CONFIG_DPP
|
||||
else if (key_mgmt & WPA_KEY_MGMT_DPP)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef CONFIG_HS20
|
||||
else if (key_mgmt & WPA_KEY_MGMT_OSEN)
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
|
||||
#endif /* CONFIG_HS20 */
|
||||
else
|
||||
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
|
||||
@ -634,12 +741,6 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
|
||||
if (ciphers & WPA_CIPHER_TKIP) {
|
||||
wpa_printf(MSG_DEBUG, "Management frame protection "
|
||||
"cannot use TKIP");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
|
||||
if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Unsupported management group "
|
||||
@ -648,14 +749,31 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL &&
|
||||
wpa_auth->conf.sae_require_mfp &&
|
||||
wpa_key_mgmt_sae(sm->wpa_key_mgmt) &&
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Management frame protection required with SAE, but client did not enable it");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC))
|
||||
sm->mgmt_frame_prot = 0;
|
||||
else
|
||||
sm->mgmt_frame_prot = 1;
|
||||
|
||||
if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Management frame protection cannot use TKIP");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
|
||||
@ -668,8 +786,25 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
|
||||
return WPA_INVALID_MDIE;
|
||||
}
|
||||
} else if (mdie != NULL) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: Trying to use non-FT AKM suite, but MDIE included");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && !owe_dh) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: No Diffie-Hellman Parameter element");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
|
||||
if (sm->pairwise < 0)
|
||||
@ -723,6 +858,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
|
||||
!sm->pmksa) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"No PMKSA cache entry found for SAE");
|
||||
return WPA_INVALID_PMKID;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"No PMKSA cache entry found for DPP");
|
||||
return WPA_INVALID_PMKID;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
|
||||
os_free(sm->wpa_ie);
|
||||
sm->wpa_ie = os_malloc(wpa_ie_len);
|
||||
@ -815,36 +967,6 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
|
||||
ie->smk = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
|
||||
ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
|
||||
ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
|
||||
ie->error = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->error_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
|
||||
@ -908,14 +1030,14 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
|
||||
if (*pos == WLAN_EID_RSN) {
|
||||
ie->rsn_ie = pos;
|
||||
ie->rsn_ie_len = pos[1] + 2;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
|
||||
ie->mdie = pos;
|
||||
ie->mdie_len = pos[1] + 2;
|
||||
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
|
||||
ie->ftie = pos;
|
||||
ie->ftie_len = pos[1] + 2;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
|
||||
ret = wpa_parse_generic(pos, end, ie);
|
||||
if (ret < 0)
|
||||
@ -938,3 +1060,36 @@ int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
|
||||
{
|
||||
return sm ? sm->mgmt_frame_prot : 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
const u8 *req_ies, size_t req_ies_len)
|
||||
{
|
||||
int res;
|
||||
struct wpa_auth_config *conf;
|
||||
|
||||
if (!sm)
|
||||
return pos;
|
||||
conf = &sm->wpa_auth->conf;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (conf->own_ie_override_len) {
|
||||
if (max_len < conf->own_ie_override_len)
|
||||
return NULL;
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
|
||||
conf->own_ie_override, conf->own_ie_override_len);
|
||||
os_memcpy(pos, conf->own_ie_override,
|
||||
conf->own_ie_override_len);
|
||||
return pos + conf->own_ie_override_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
res = wpa_write_rsn_ie(conf, pos, max_len,
|
||||
sm->pmksa ? sm->pmksa->pmkid : NULL);
|
||||
if (res < 0)
|
||||
return pos;
|
||||
return pos + res;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
@ -19,26 +19,16 @@ struct wpa_eapol_ie_parse {
|
||||
size_t gtk_len;
|
||||
const u8 *mac_addr;
|
||||
size_t mac_addr_len;
|
||||
#ifdef CONFIG_PEERKEY
|
||||
const u8 *smk;
|
||||
size_t smk_len;
|
||||
const u8 *nonce;
|
||||
size_t nonce_len;
|
||||
const u8 *lifetime;
|
||||
size_t lifetime_len;
|
||||
const u8 *error;
|
||||
size_t error_len;
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
const u8 *igtk;
|
||||
size_t igtk_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
const u8 *mdie;
|
||||
size_t mdie_len;
|
||||
const u8 *ftie;
|
||||
size_t ftie_len;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_P2P
|
||||
const u8 *ip_addr_req;
|
||||
const u8 *ip_addr_alloc;
|
||||
|
@ -1064,7 +1064,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
wps->auth_types |= WPS_AUTH_WPA2;
|
||||
|
||||
if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
|
||||
if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 |
|
||||
WPA_CIPHER_GCMP_256)) {
|
||||
wps->encr_types |= WPS_ENCR_AES;
|
||||
wps->encr_types_rsn |= WPS_ENCR_AES;
|
||||
}
|
||||
|
@ -53,12 +53,38 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
|
||||
18, ParseOK, 9 },
|
||||
{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
|
||||
{ (u8 *) "\xed\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xef\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xef\x01\x11", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xf0\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xf1\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xf1\x02\x11\x22", 4, ParseOK, 1 },
|
||||
{ (u8 *) "\xf2\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
|
||||
{ (u8 *) "\xff\x01\x00", 3, ParseUnknown, 1 },
|
||||
{ (u8 *) "\xff\x01\x01", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x02\x01\x00", 4, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x02", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x04\x02\x11\x22\x33", 6, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x04", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x05", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x0d\x05\x11\x22\x33\x44\x55\x55\x11\x22\x33\x44\x55\x55",
|
||||
15, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x06", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x02\x06\x00", 4, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x07", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x09\x07\x11\x22\x33\x44\x55\x66\x77\x88", 11,
|
||||
ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x0c", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x02\x0c\x00", 4, ParseOK, 1 },
|
||||
{ (u8 *) "\xff\x01\x0d", 3, ParseOK, 1 },
|
||||
{ NULL, 0, ParseOK, 0 }
|
||||
};
|
||||
|
||||
static int ieee802_11_parse_tests(void)
|
||||
{
|
||||
int i, ret = 0;
|
||||
struct wpabuf *buf;
|
||||
|
||||
wpa_printf(MSG_INFO, "ieee802_11_parse tests");
|
||||
|
||||
@ -84,6 +110,35 @@ static int ieee802_11_parse_tests(void)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
buf = ieee802_11_vendor_ie_concat((const u8 *) "\xdd\x05\x11\x22\x33\x44\x01\xdd\x05\x11\x22\x33\x44\x02\x00\x01",
|
||||
16, 0x11223344);
|
||||
do {
|
||||
const u8 *pos;
|
||||
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ieee802_11_vendor_ie_concat test 2 failed");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wpabuf_len(buf) != 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ieee802_11_vendor_ie_concat test 3 failed");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
pos = wpabuf_head(buf);
|
||||
if (pos[0] != 0x01 || pos[1] != 0x02) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ieee802_11_vendor_ie_concat test 3 failed");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -113,17 +113,53 @@ void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
|
||||
}
|
||||
|
||||
|
||||
static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
|
||||
{
|
||||
const char *value;
|
||||
int val;
|
||||
|
||||
if (!input)
|
||||
return 0;
|
||||
|
||||
value = os_strchr(input, '=');
|
||||
if (!value)
|
||||
return -1;
|
||||
value++;
|
||||
val = atoi(value);
|
||||
if (val < 0 || val > 1)
|
||||
return -1;
|
||||
|
||||
if (str_starts(input, "probe_rx_events=")) {
|
||||
if (val)
|
||||
dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
|
||||
else
|
||||
dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen)
|
||||
socklen_t fromlen, const char *input)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
/* Update event registration if already attached */
|
||||
dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
|
||||
if (!sockaddr_compare(from, fromlen,
|
||||
&dst->addr, dst->addrlen))
|
||||
return ctrl_set_events(dst, input);
|
||||
}
|
||||
|
||||
/* New attachment */
|
||||
dst = os_zalloc(sizeof(*dst));
|
||||
if (dst == NULL)
|
||||
return -1;
|
||||
os_memcpy(&dst->addr, from, fromlen);
|
||||
dst->addrlen = fromlen;
|
||||
dst->debug_level = MSG_INFO;
|
||||
ctrl_set_events(dst, input);
|
||||
dl_list_add(ctrl_dst, &dst->list);
|
||||
|
||||
sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
#include "utils/list.h"
|
||||
|
||||
/* Events enable bits (wpa_ctrl_dst::events) */
|
||||
#define WPA_EVENT_RX_PROBE_REQUEST BIT(0)
|
||||
|
||||
/**
|
||||
* struct wpa_ctrl_dst - Data structure of control interface monitors
|
||||
*
|
||||
@ -23,13 +26,14 @@ struct wpa_ctrl_dst {
|
||||
socklen_t addrlen;
|
||||
int debug_level;
|
||||
int errors;
|
||||
u32 events; /* WPA_EVENT_* bitmap */
|
||||
};
|
||||
|
||||
void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
|
||||
socklen_t socklen);
|
||||
|
||||
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen);
|
||||
socklen_t fromlen, const char *input);
|
||||
int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen);
|
||||
int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* WPA Supplicant - Common definitions
|
||||
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -51,16 +51,28 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
|
||||
#define WPA_KEY_MGMT_OSEN BIT(15)
|
||||
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
|
||||
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
|
||||
#define WPA_KEY_MGMT_FILS_SHA256 BIT(18)
|
||||
#define WPA_KEY_MGMT_FILS_SHA384 BIT(19)
|
||||
#define WPA_KEY_MGMT_FT_FILS_SHA256 BIT(20)
|
||||
#define WPA_KEY_MGMT_FT_FILS_SHA384 BIT(21)
|
||||
#define WPA_KEY_MGMT_OWE BIT(22)
|
||||
#define WPA_KEY_MGMT_DPP BIT(23)
|
||||
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
|
||||
WPA_KEY_MGMT_CCKM |
|
||||
WPA_KEY_MGMT_OSEN |
|
||||
WPA_KEY_MGMT_IEEE8021X_SHA256 |
|
||||
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
|
||||
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
|
||||
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
|
||||
WPA_KEY_MGMT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_psk(int akm)
|
||||
@ -76,7 +88,15 @@ static inline int wpa_key_mgmt_ft(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X |
|
||||
WPA_KEY_MGMT_FT_SAE));
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_ft_psk(int akm)
|
||||
{
|
||||
return !!(akm & WPA_KEY_MGMT_FT_PSK);
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_sae(int akm)
|
||||
@ -85,17 +105,32 @@ static inline int wpa_key_mgmt_sae(int akm)
|
||||
WPA_KEY_MGMT_FT_SAE));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_fils(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_sha256(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
|
||||
WPA_KEY_MGMT_IEEE8021X_SHA256 |
|
||||
WPA_KEY_MGMT_SAE |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
WPA_KEY_MGMT_OSEN |
|
||||
WPA_KEY_MGMT_IEEE8021X_SUITE_B));
|
||||
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
|
||||
WPA_KEY_MGMT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_sha384(int akm)
|
||||
{
|
||||
return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
|
||||
return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
|
||||
WPA_KEY_MGMT_FILS_SHA384 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_suite_b(int akm)
|
||||
@ -108,7 +143,10 @@ static inline int wpa_key_mgmt_wpa(int akm)
|
||||
{
|
||||
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
|
||||
wpa_key_mgmt_wpa_psk(akm) ||
|
||||
wpa_key_mgmt_sae(akm);
|
||||
wpa_key_mgmt_fils(akm) ||
|
||||
wpa_key_mgmt_sae(akm) ||
|
||||
akm == WPA_KEY_MGMT_OWE ||
|
||||
akm == WPA_KEY_MGMT_DPP;
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_any(int akm)
|
||||
@ -132,7 +170,13 @@ static inline int wpa_key_mgmt_cckm(int akm)
|
||||
#define WPA_AUTH_ALG_LEAP BIT(2)
|
||||
#define WPA_AUTH_ALG_FT BIT(3)
|
||||
#define WPA_AUTH_ALG_SAE BIT(4)
|
||||
#define WPA_AUTH_ALG_FILS BIT(5)
|
||||
#define WPA_AUTH_ALG_FILS_SK_PFS BIT(6)
|
||||
|
||||
static inline int wpa_auth_alg_fils(int alg)
|
||||
{
|
||||
return !!(alg & (WPA_AUTH_ALG_FILS | WPA_AUTH_ALG_FILS_SK_PFS));
|
||||
}
|
||||
|
||||
enum wpa_alg {
|
||||
WPA_ALG_NONE,
|
||||
@ -341,4 +385,18 @@ enum wpa_radio_work_band {
|
||||
BAND_60_GHZ = BIT(2),
|
||||
};
|
||||
|
||||
enum beacon_rate_type {
|
||||
BEACON_RATE_LEGACY,
|
||||
BEACON_RATE_HT,
|
||||
BEACON_RATE_VHT
|
||||
};
|
||||
|
||||
enum eap_proxy_sim_state {
|
||||
SIM_STATE_ERROR,
|
||||
};
|
||||
|
||||
#define OCE_STA BIT(0)
|
||||
#define OCE_STA_CFON BIT(1)
|
||||
#define OCE_AP BIT(2)
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
279
contrib/wpa/src/common/dhcp.h
Normal file
279
contrib/wpa/src/common/dhcp.h
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* DHCP definitions
|
||||
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DHCP_H
|
||||
#define DHCP_H
|
||||
|
||||
/*
|
||||
* Translate Linux to FreeBSD
|
||||
*/
|
||||
#define iphdr ip
|
||||
#define ihl ip_hl
|
||||
#define verson ip_v
|
||||
#define tos ip_tos
|
||||
#define tot_len ip_len
|
||||
#define id ip_id
|
||||
#define frag_off ip_off
|
||||
#define ttl ip_ttl
|
||||
#define protocol ip_p
|
||||
#define check ip_sum
|
||||
#define saddr ip_src
|
||||
#define daddr ip_dst
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#if __FAVOR_BSD
|
||||
#include <netinet/udp.h>
|
||||
#else
|
||||
#define __FAVOR_BSD 1
|
||||
#include <netinet/udp.h>
|
||||
#undef __FAVOR_BSD
|
||||
#endif
|
||||
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
struct dhcp_data {
|
||||
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];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
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 DHCP_MAGIC 0x63825363
|
||||
|
||||
/*
|
||||
* IANA DHCP/BOOTP registry
|
||||
* http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
|
||||
*/
|
||||
enum dhcp_options {
|
||||
DHCP_OPT_PAD = 0,
|
||||
DHCP_OPT_SUBNET_MASK = 1,
|
||||
DHCP_OPT_TIME_OFFSET = 2,
|
||||
DHCP_OPT_ROUTER = 3,
|
||||
DHCP_OPT_TIME_SERVER = 4,
|
||||
DHCP_OPT_NAME_SERVER = 5,
|
||||
DHCP_OPT_DOMAIN_NAME_SERVER = 6,
|
||||
DHCP_OPT_LOG_SERVER = 7,
|
||||
DHCP_OPT_QUOTES_SERVER = 8,
|
||||
DHCP_OPT_LPR_SERVER = 9,
|
||||
DHCP_OPT_IMPRESS_SERVER = 10,
|
||||
DHCP_OPT_RLP_SERVER = 11,
|
||||
DHCP_OPT_HOSTNAME = 12,
|
||||
DHCP_OPT_BOOT_FILE_SIZE = 13,
|
||||
DHCP_OPT_MERIT_DUMP_FILE = 14,
|
||||
DHCP_OPT_DOMAIN_NAME = 15,
|
||||
DHCP_OPT_SWAP_SERVER = 16,
|
||||
DHCP_OPT_ROOT_PATH = 17,
|
||||
DHCP_OPT_EXTENSION_PATH = 18,
|
||||
DHCP_OPT_FORWARD = 19,
|
||||
DHCP_OPT_SRC_RTE = 20,
|
||||
DHCP_OPT_POLICY_FILTER = 21,
|
||||
DHCP_OPT_MAX_DG_ASSEMBLY = 22,
|
||||
DHCP_OPT_DEFAULT_IP_TTL = 23,
|
||||
DHCP_OPT_MTU_TIMEOUT = 24,
|
||||
DHCP_OPT_MTU_PLATEAU = 25,
|
||||
DHCP_OPT_MTU_INTERFACE = 26,
|
||||
DHCP_OPT_ALL_SUBNETS_LOCAL = 27,
|
||||
DHCP_OPT_BROADCAST_ADDRESS = 28,
|
||||
DHCP_OPT_MASK_DISCOVERY = 29,
|
||||
DHCP_OPT_MASK_SUPPLIER = 30,
|
||||
DHCP_OPT_ROUTER_DISCOVERY = 31,
|
||||
DHCP_OPT_ROUTER_SOLICITATION_ADDRESS = 32,
|
||||
DHCP_OPT_STATIC_ROUTE = 33,
|
||||
DHCP_OPT_TRAILERS = 34,
|
||||
DHCP_OPT_ARP_TIMEOUT = 35,
|
||||
DHCP_OPT_ETHERNET = 36,
|
||||
DHCP_OPT_TCP_DEFAULT_TTL = 37,
|
||||
DHCP_OPT_TCP_KEEPALIVE_INTERVAL = 38,
|
||||
DHCP_OPT_TCP_KEEPALIVE_GARBAGE = 39,
|
||||
DHCP_OPT_NIS_DOMAIN = 40,
|
||||
DHCP_OPT_NIS_SERVERS = 41,
|
||||
DHCP_OPT_NTP_SERVERS = 42,
|
||||
DHCP_OPT_VENDOR_SPECIFIC = 43,
|
||||
DHCP_OPT_NETBIOS_NAME_SERVER = 44,
|
||||
DHCP_OPT_NETBIOS_DISTRIBUTION_SERVER = 45,
|
||||
DHCP_OPT_NETBIOS_NODE_TYPE = 46,
|
||||
DHCP_OPT_NETBIOS_SCOPE = 47,
|
||||
DHCP_OPT_FONT_SERVER = 48,
|
||||
DHCP_OPT_DISPLAY_MANAGER = 49,
|
||||
DHCP_OPT_REQUESTED_IP_ADDRESS = 50,
|
||||
DHCP_OPT_IP_ADDRESS_LEASE_TIME = 51,
|
||||
DHCP_OPT_OVERLOAD = 52,
|
||||
DHCP_OPT_MSG_TYPE = 53,
|
||||
DHCP_OPT_SERVER_ID = 54,
|
||||
DHCP_OPT_PARAMETER_REQ_LIST = 55,
|
||||
DHCP_OPT_MESSAGE = 56,
|
||||
DHCP_OPT_MAX_MESSAGE_SIZE = 57,
|
||||
DHCP_OPT_RENEWAL_TIME = 58,
|
||||
DHCP_OPT_REBINDING_TIME = 59,
|
||||
DHCP_OPT_VENDOR_CLASS_ID = 60,
|
||||
DHCP_OPT_CLIENT_ID = 61,
|
||||
DHCP_OPT_NETWARE_IP_DOMAIN = 62,
|
||||
DHCP_OPT_NETWARE_IP_OPTION = 63,
|
||||
DHCP_OPT_NIS_V3_DOMAIN = 64,
|
||||
DHCP_OPT_NIS_V3_SERVERS = 65,
|
||||
DHCP_OPT_TFTP_SERVER_NAME = 66,
|
||||
DHCP_OPT_BOOT_FILE_NAME = 67,
|
||||
DHCP_OPT_HOME_AGENT_ADDRESSES = 68,
|
||||
DHCP_OPT_SMTP_SERVER = 69,
|
||||
DHCP_OPT_POP3_SERVER = 70,
|
||||
DHCP_OPT_NNTP_SERVER = 71,
|
||||
DHCP_OPT_WWW_SERVER = 72,
|
||||
DHCP_OPT_FINGER_SERVER = 73,
|
||||
DHCP_OPT_IRC_SERVER = 74,
|
||||
DHCP_OPT_STREETTALK_SERVER = 75,
|
||||
DHCP_OPT_STDA_SERVER = 76,
|
||||
DHCP_OPT_USER_CLASS = 77,
|
||||
DHCP_OPT_DIRECTORY_AGENT = 78,
|
||||
DHCP_OPT_SERVICE_SCOPE = 79,
|
||||
DHCP_OPT_RAPID_COMMIT = 80,
|
||||
DHCP_OPT_CLIENT_FQDN = 81,
|
||||
DHCP_OPT_RELAY_AGENT_INFO = 82,
|
||||
DHCP_OPT_ISNS = 83,
|
||||
DHCP_OPT_NDS_SERVERS = 85,
|
||||
DHCP_OPT_NDS_TREE_NAME = 86,
|
||||
DHCP_OPT_NDS_CONTEXT = 87,
|
||||
DHCP_OPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
|
||||
DHCP_OPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
|
||||
DHCP_OPT_AUTHENTICATION = 90,
|
||||
DHCP_OPT_CLIENT_LAST_TRANSACTION_TIME = 91,
|
||||
DHCP_OPT_ASSOCIATED_IP = 92,
|
||||
DHCP_OPT_CLIENT_SYSYEM = 93,
|
||||
DHCP_OPT_CLIENT_NDI = 94,
|
||||
DHCP_OPT_LDAP = 95,
|
||||
DHCP_OPT_UUID_GUID = 97,
|
||||
DHCP_OPT_USER_AUTH = 98,
|
||||
DHCP_OPT_GEOCONF_CIVIC = 99,
|
||||
DHCP_OPT_PCODE = 100,
|
||||
DHCP_OPT_TCODE = 101,
|
||||
DHCP_OPT_NETINFO_ADDRESS = 112,
|
||||
DHCP_OPT_NETINFO_TAG = 113,
|
||||
DHCP_OPT_URL = 114,
|
||||
DHCP_OPT_AUTO_CONFIG = 116,
|
||||
DHCP_OPT_NAME_SERVICE_SEARCH = 117,
|
||||
DHCP_OPT_SUBNET_SELECTION = 118,
|
||||
DHCP_OPT_DOMAIN_SEARCH = 119,
|
||||
DHCP_OPT_SIP_SERVERS_DCP = 120,
|
||||
DHCP_OPT_CLASSLESS_STATIC_ROUTE = 121,
|
||||
DHCP_OPT_CCC = 122,
|
||||
DHCP_OPT_GEOCONF = 123,
|
||||
DHCP_OPT_V_I_VENDOR_CLASS = 124,
|
||||
DHCP_OPT_V_I_VENDOR_SPECIFIC_INFO = 125,
|
||||
DHCP_OPT_PANA_AGENT = 136,
|
||||
DHCP_OPT_V4_LOST = 137,
|
||||
DHCP_OPT_CAPWAP_AC_V4 = 138,
|
||||
DHCP_OPT_IPV4_ADDRESS_MOS = 139,
|
||||
DHCP_OPT_IPV4_FQDN_MOS = 140,
|
||||
DHCP_OPT_SIP_UA_CONF = 141,
|
||||
DHCP_OPT_IPV4_ADDRESS_ANDSF = 142,
|
||||
DHCP_OPT_GEOLOC = 144,
|
||||
DHCP_OPT_FORCERENEW_NONCE_CAPABLE = 145,
|
||||
DHCP_OPT_RDNSS_SELECTION = 146,
|
||||
DHCP_OPT_TFTP_SERVER_ADDRESS = 150,
|
||||
DHCP_OPT_STATUS_CODE = 151,
|
||||
DHCP_OPT_BASE_TIME = 152,
|
||||
DHCP_OPT_START_TIME_OF_STATE = 153,
|
||||
DHCP_OPT_QUERY_START_TIME = 154,
|
||||
DHCP_OPT_QUERY_END_TIME = 155,
|
||||
DHCP_OPT_STATE = 156,
|
||||
DHCP_OPT_DATA_SOURCE = 157,
|
||||
DHCP_OPT_V4_PCP_SERVER = 158,
|
||||
DHCP_OPT_V4_PORTPARAMS = 159,
|
||||
DHCP_OPT_CAPTIVE_PORTAL = 160,
|
||||
DHCP_OPT_CONF_FILE = 209,
|
||||
DHCP_OPT_PATH_PREFIX = 210,
|
||||
DHCP_OPT_REBOOT_TIME = 211,
|
||||
DHCP_OPT_6RD = 212,
|
||||
DHCP_OPT_V4_ACCESS_DOMAIN = 213,
|
||||
DHCP_OPT_SUBNET_ALLOCATION = 220,
|
||||
DHCP_OPT_VSS = 221,
|
||||
DHCP_OPT_END = 255
|
||||
};
|
||||
|
||||
enum dhcp_message_types {
|
||||
DHCPDISCOVER = 1,
|
||||
DHCPOFFER = 2,
|
||||
DHCPREQUEST = 3,
|
||||
DHCPDECLINE = 4,
|
||||
DHCPACK = 5,
|
||||
DHCPNAK = 6,
|
||||
DHCPRELEASE = 7,
|
||||
DHCPINFORM = 8,
|
||||
DHCPFORCERENEW = 9,
|
||||
DHCPLEASEQUERY = 10,
|
||||
DHCPLEASEUNASSIGNED = 11,
|
||||
DHCPLEASEUNKNOWN = 12,
|
||||
DHCPLEASEACTIVE = 13,
|
||||
DHCPBULKLEASEQUERY = 14,
|
||||
DHCPLEASEQUERYDONE = 15,
|
||||
DHCPACTIVELEASEQUERY = 16,
|
||||
DHCPLEASEQUERYSTATUS = 17,
|
||||
DHCPTLS = 18,
|
||||
};
|
||||
|
||||
enum dhcp_relay_agent_suboptions {
|
||||
DHCP_RELAY_OPT_AGENT_CIRCUIT_ID = 1,
|
||||
DHCP_RELAY_OPT_AGENT_REMOTE_ID = 2,
|
||||
DHCP_RELAY_OPT_DOCSIS_DEVICE_CLASS = 4,
|
||||
DHCP_RELAY_OPT_LINK_SELECTION = 5,
|
||||
DHCP_RELAY_OPT_SUBSCRIBE_ID = 6,
|
||||
DHCP_RELAY_OPT_RADIUS_ATTRIBUTES = 7,
|
||||
DHCP_RELAY_OPT_AUTHENTICATION = 8,
|
||||
DHCP_RELAY_OPT_VEDOR_SPECIFIC = 9,
|
||||
DHCP_RELAY_OPT_RELAY_AGENT_FLAGS = 10,
|
||||
DHCP_RELAY_OPT_SERVER_ID_OVERRIDE = 11,
|
||||
DHCP_RELAY_OPT_RELAY_AGENT_ID = 12,
|
||||
DHCP_RELAY_OPT_ACCESS_TECHNOLOGY_TYPE = 13,
|
||||
DHCP_RELAY_OPT_ACCESS_NETWORK_NAME = 14,
|
||||
DHCP_RELAY_OPT_ACCESS_POINT_NAME = 15,
|
||||
DHCP_RELAY_OPT_ACCESS_POINT_BSSID = 16,
|
||||
DHCP_RELAY_OPT_OPERATOR_ID = 17,
|
||||
DHCP_RELAY_OPT_OPERATOR_REALM = 18,
|
||||
DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION = 151,
|
||||
DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION_CONTROL = 152,
|
||||
};
|
||||
|
||||
enum access_technology_types {
|
||||
ACCESS_TECHNOLOGY_VIRTUAL = 1,
|
||||
ACCESS_TECHNOLOGY_PPP = 2,
|
||||
ACCESS_TECHNOLOGY_ETHERNET = 3,
|
||||
ACCESS_TECHNOLOGY_WLAN = 4,
|
||||
ACCESS_TECHNOLOGY_WIMAX = 5,
|
||||
};
|
||||
|
||||
#endif /* DHCP_H */
|
7691
contrib/wpa/src/common/dpp.c
Normal file
7691
contrib/wpa/src/common/dpp.c
Normal file
File diff suppressed because it is too large
Load Diff
435
contrib/wpa/src/common/dpp.h
Normal file
435
contrib/wpa/src/common/dpp.h
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* DPP functionality shared between hostapd and wpa_supplicant
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPP_H
|
||||
#define DPP_H
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "utils/list.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
|
||||
|
||||
enum dpp_public_action_frame_type {
|
||||
DPP_PA_AUTHENTICATION_REQ = 0,
|
||||
DPP_PA_AUTHENTICATION_RESP = 1,
|
||||
DPP_PA_AUTHENTICATION_CONF = 2,
|
||||
DPP_PA_PEER_DISCOVERY_REQ = 5,
|
||||
DPP_PA_PEER_DISCOVERY_RESP = 6,
|
||||
DPP_PA_PKEX_EXCHANGE_REQ = 7,
|
||||
DPP_PA_PKEX_EXCHANGE_RESP = 8,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
|
||||
};
|
||||
|
||||
enum dpp_attribute_id {
|
||||
DPP_ATTR_STATUS = 0x1000,
|
||||
DPP_ATTR_I_BOOTSTRAP_KEY_HASH = 0x1001,
|
||||
DPP_ATTR_R_BOOTSTRAP_KEY_HASH = 0x1002,
|
||||
DPP_ATTR_I_PROTOCOL_KEY = 0x1003,
|
||||
DPP_ATTR_WRAPPED_DATA = 0x1004,
|
||||
DPP_ATTR_I_NONCE = 0x1005,
|
||||
DPP_ATTR_I_CAPABILITIES = 0x1006,
|
||||
DPP_ATTR_R_NONCE = 0x1007,
|
||||
DPP_ATTR_R_CAPABILITIES = 0x1008,
|
||||
DPP_ATTR_R_PROTOCOL_KEY = 0x1009,
|
||||
DPP_ATTR_I_AUTH_TAG = 0x100A,
|
||||
DPP_ATTR_R_AUTH_TAG = 0x100B,
|
||||
DPP_ATTR_CONFIG_OBJ = 0x100C,
|
||||
DPP_ATTR_CONNECTOR = 0x100D,
|
||||
DPP_ATTR_CONFIG_ATTR_OBJ = 0x100E,
|
||||
DPP_ATTR_BOOTSTRAP_KEY = 0x100F,
|
||||
DPP_ATTR_OWN_NET_NK_HASH = 0x1011,
|
||||
DPP_ATTR_FINITE_CYCLIC_GROUP = 0x1012,
|
||||
DPP_ATTR_ENCRYPTED_KEY = 0x1013,
|
||||
DPP_ATTR_ENROLLEE_NONCE = 0x1014,
|
||||
DPP_ATTR_CODE_IDENTIFIER = 0x1015,
|
||||
DPP_ATTR_TRANSACTION_ID = 0x1016,
|
||||
DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
|
||||
DPP_ATTR_CHANNEL = 0x1018,
|
||||
};
|
||||
|
||||
enum dpp_status_error {
|
||||
DPP_STATUS_OK = 0,
|
||||
DPP_STATUS_NOT_COMPATIBLE = 1,
|
||||
DPP_STATUS_AUTH_FAILURE = 2,
|
||||
DPP_STATUS_UNWRAP_FAILURE = 3,
|
||||
DPP_STATUS_BAD_GROUP = 4,
|
||||
DPP_STATUS_CONFIGURE_FAILURE = 5,
|
||||
DPP_STATUS_RESPONSE_PENDING = 6,
|
||||
DPP_STATUS_INVALID_CONNECTOR = 7,
|
||||
DPP_STATUS_NO_MATCH = 8,
|
||||
};
|
||||
|
||||
#define DPP_CAPAB_ENROLLEE BIT(0)
|
||||
#define DPP_CAPAB_CONFIGURATOR BIT(1)
|
||||
#define DPP_CAPAB_ROLE_MASK (BIT(0) | BIT(1))
|
||||
|
||||
#define DPP_BOOTSTRAP_MAX_FREQ 30
|
||||
#define DPP_MAX_NONCE_LEN 32
|
||||
#define DPP_MAX_HASH_LEN 64
|
||||
#define DPP_MAX_SHARED_SECRET_LEN 66
|
||||
|
||||
struct dpp_curve_params {
|
||||
const char *name;
|
||||
size_t hash_len;
|
||||
size_t aes_siv_key_len;
|
||||
size_t nonce_len;
|
||||
size_t prime_len;
|
||||
const char *jwk_crv;
|
||||
u16 ike_group;
|
||||
const char *jws_alg;
|
||||
};
|
||||
|
||||
enum dpp_bootstrap_type {
|
||||
DPP_BOOTSTRAP_QR_CODE,
|
||||
DPP_BOOTSTRAP_PKEX,
|
||||
};
|
||||
|
||||
struct dpp_bootstrap_info {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
enum dpp_bootstrap_type type;
|
||||
char *uri;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
char *info;
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq;
|
||||
int own;
|
||||
EVP_PKEY *pubkey;
|
||||
u8 pubkey_hash[SHA256_MAC_LEN];
|
||||
const struct dpp_curve_params *curve;
|
||||
unsigned int pkex_t; /* number of failures before dpp_pkex
|
||||
* instantiation */
|
||||
};
|
||||
|
||||
#define PKEX_COUNTER_T_LIMIT 5
|
||||
|
||||
struct dpp_pkex {
|
||||
void *msg_ctx;
|
||||
unsigned int initiator:1;
|
||||
unsigned int exchange_done:1;
|
||||
unsigned int failed:1;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
u8 own_mac[ETH_ALEN];
|
||||
u8 peer_mac[ETH_ALEN];
|
||||
char *identifier;
|
||||
char *code;
|
||||
EVP_PKEY *x;
|
||||
EVP_PKEY *y;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 z[DPP_MAX_HASH_LEN];
|
||||
EVP_PKEY *peer_bootstrap_key;
|
||||
struct wpabuf *exchange_req;
|
||||
struct wpabuf *exchange_resp;
|
||||
unsigned int t; /* number of failures on code use */
|
||||
unsigned int exch_req_wait_time;
|
||||
unsigned int exch_req_tries;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
enum dpp_akm {
|
||||
DPP_AKM_UNKNOWN,
|
||||
DPP_AKM_DPP,
|
||||
DPP_AKM_PSK,
|
||||
DPP_AKM_SAE,
|
||||
DPP_AKM_PSK_SAE
|
||||
};
|
||||
|
||||
struct dpp_configuration {
|
||||
u8 ssid[32];
|
||||
size_t ssid_len;
|
||||
enum dpp_akm akm;
|
||||
|
||||
/* For DPP configuration (connector) */
|
||||
os_time_t netaccesskey_expiry;
|
||||
|
||||
/* TODO: groups */
|
||||
char *group_id;
|
||||
|
||||
/* For legacy configuration */
|
||||
char *passphrase;
|
||||
u8 psk[32];
|
||||
};
|
||||
|
||||
struct dpp_authentication {
|
||||
void *msg_ctx;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
struct dpp_bootstrap_info *tmp_own_bi;
|
||||
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
|
||||
int response_pending;
|
||||
enum dpp_status_error auth_resp_status;
|
||||
u8 peer_mac_addr[ETH_ALEN];
|
||||
u8 i_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 r_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 e_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 i_capab;
|
||||
u8 r_capab;
|
||||
EVP_PKEY *own_protocol_key;
|
||||
EVP_PKEY *peer_protocol_key;
|
||||
struct wpabuf *req_msg;
|
||||
struct wpabuf *resp_msg;
|
||||
/* Intersection of possible frequencies for initiating DPP
|
||||
* Authentication exchange */
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq, freq_idx;
|
||||
unsigned int curr_freq;
|
||||
unsigned int neg_freq;
|
||||
unsigned int num_freq_iters;
|
||||
size_t secret_len;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Mx_len;
|
||||
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Nx_len;
|
||||
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Lx_len;
|
||||
u8 k1[DPP_MAX_HASH_LEN];
|
||||
u8 k2[DPP_MAX_HASH_LEN];
|
||||
u8 ke[DPP_MAX_HASH_LEN];
|
||||
int initiator;
|
||||
int waiting_auth_resp;
|
||||
int waiting_auth_conf;
|
||||
int auth_req_ack;
|
||||
unsigned int auth_resp_tries;
|
||||
u8 allowed_roles;
|
||||
int configurator;
|
||||
int remove_on_tx_status;
|
||||
int auth_success;
|
||||
struct wpabuf *conf_req;
|
||||
const struct wpabuf *conf_resp; /* owned by GAS server */
|
||||
struct dpp_configuration *conf_ap;
|
||||
struct dpp_configuration *conf_sta;
|
||||
struct dpp_configurator *conf;
|
||||
char *connector; /* received signedConnector */
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
u8 ssid_len;
|
||||
char passphrase[64];
|
||||
u8 psk[PMK_LEN];
|
||||
int psk_set;
|
||||
enum dpp_akm akm;
|
||||
struct wpabuf *net_access_key;
|
||||
os_time_t net_access_key_expiry;
|
||||
struct wpabuf *c_sign_key;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *config_obj_override;
|
||||
char *discovery_override;
|
||||
char *groups_override;
|
||||
unsigned int ignore_netaccesskey_mismatch:1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
struct dpp_configurator {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
int own;
|
||||
EVP_PKEY *csign;
|
||||
char *kid;
|
||||
const struct dpp_curve_params *curve;
|
||||
};
|
||||
|
||||
struct dpp_introduction {
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
enum dpp_test_behavior {
|
||||
DPP_TEST_DISABLED = 0,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7,
|
||||
DPP_TEST_ZERO_I_CAPAB = 8,
|
||||
DPP_TEST_ZERO_R_CAPAB = 9,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 10,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 11,
|
||||
DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ = 12,
|
||||
DPP_TEST_NO_I_NONCE_AUTH_REQ = 13,
|
||||
DPP_TEST_NO_I_CAPAB_AUTH_REQ = 14,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ = 15,
|
||||
DPP_TEST_NO_STATUS_AUTH_RESP = 16,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 17,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 18,
|
||||
DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP = 19,
|
||||
DPP_TEST_NO_R_NONCE_AUTH_RESP = 20,
|
||||
DPP_TEST_NO_I_NONCE_AUTH_RESP = 21,
|
||||
DPP_TEST_NO_R_CAPAB_AUTH_RESP = 22,
|
||||
DPP_TEST_NO_R_AUTH_AUTH_RESP = 23,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP = 24,
|
||||
DPP_TEST_NO_STATUS_AUTH_CONF = 25,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 26,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 27,
|
||||
DPP_TEST_NO_I_AUTH_AUTH_CONF = 28,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF = 29,
|
||||
DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP = 30,
|
||||
DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP = 31,
|
||||
DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP = 32,
|
||||
DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF = 33,
|
||||
DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ = 34,
|
||||
DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 35,
|
||||
DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP = 36,
|
||||
DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 37,
|
||||
DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ = 38,
|
||||
DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ = 39,
|
||||
DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ = 40,
|
||||
DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP = 41,
|
||||
DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP = 42,
|
||||
DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP = 43,
|
||||
DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 44,
|
||||
DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 45,
|
||||
DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP = 46,
|
||||
DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ = 47,
|
||||
DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP = 48,
|
||||
DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ = 49,
|
||||
DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP = 50,
|
||||
DPP_TEST_NO_E_NONCE_CONF_REQ = 51,
|
||||
DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ = 52,
|
||||
DPP_TEST_NO_WRAPPED_DATA_CONF_REQ = 53,
|
||||
DPP_TEST_NO_E_NONCE_CONF_RESP = 54,
|
||||
DPP_TEST_NO_CONFIG_OBJ_CONF_RESP = 55,
|
||||
DPP_TEST_NO_STATUS_CONF_RESP = 56,
|
||||
DPP_TEST_NO_WRAPPED_DATA_CONF_RESP = 57,
|
||||
DPP_TEST_INVALID_STATUS_CONF_RESP = 58,
|
||||
DPP_TEST_E_NONCE_MISMATCH_CONF_RESP = 59,
|
||||
DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ = 60,
|
||||
DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ = 61,
|
||||
DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP = 62,
|
||||
DPP_TEST_NO_STATUS_PEER_DISC_RESP = 63,
|
||||
DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP = 64,
|
||||
DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF = 65,
|
||||
DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ = 66,
|
||||
DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP = 67,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 68,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 69,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 70,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 71,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 72,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 73,
|
||||
DPP_TEST_INVALID_STATUS_AUTH_RESP = 74,
|
||||
DPP_TEST_INVALID_STATUS_AUTH_CONF = 75,
|
||||
DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ = 76,
|
||||
DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP = 77,
|
||||
DPP_TEST_INVALID_STATUS_PEER_DISC_RESP = 78,
|
||||
DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP = 79,
|
||||
DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ = 80,
|
||||
DPP_TEST_INVALID_I_NONCE_AUTH_REQ = 81,
|
||||
DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ = 82,
|
||||
DPP_TEST_INVALID_E_NONCE_CONF_REQ = 83,
|
||||
DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP = 84,
|
||||
DPP_TEST_STOP_AT_PKEX_CR_REQ = 85,
|
||||
DPP_TEST_STOP_AT_PKEX_CR_RESP = 86,
|
||||
DPP_TEST_STOP_AT_AUTH_REQ = 87,
|
||||
DPP_TEST_STOP_AT_AUTH_RESP = 88,
|
||||
DPP_TEST_STOP_AT_AUTH_CONF = 89,
|
||||
DPP_TEST_STOP_AT_CONF_REQ = 90,
|
||||
};
|
||||
|
||||
extern enum dpp_test_behavior dpp_test;
|
||||
extern u8 dpp_pkex_own_mac_override[ETH_ALEN];
|
||||
extern u8 dpp_pkex_peer_mac_override[ETH_ALEN];
|
||||
extern u8 dpp_pkex_ephemeral_key_override[600];
|
||||
extern size_t dpp_pkex_ephemeral_key_override_len;
|
||||
extern u8 dpp_protocol_key_override[600];
|
||||
extern size_t dpp_protocol_key_override_len;
|
||||
extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
|
||||
extern size_t dpp_nonce_override_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
|
||||
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
|
||||
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
|
||||
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
|
||||
const char *chan_list);
|
||||
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
|
||||
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
|
||||
struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri);
|
||||
char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
|
||||
const u8 *privkey, size_t privkey_len);
|
||||
struct hostapd_hw_modes;
|
||||
struct dpp_authentication * dpp_auth_init(void *msg_ctx,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
u8 dpp_allowed_roles,
|
||||
unsigned int neg_freq,
|
||||
struct hostapd_hw_modes *own_modes,
|
||||
u16 num_modes);
|
||||
struct dpp_authentication *
|
||||
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
unsigned int freq, const u8 *hdr, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
struct wpabuf *
|
||||
dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
|
||||
const char *json);
|
||||
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
void dpp_configuration_free(struct dpp_configuration *conf);
|
||||
void dpp_auth_deinit(struct dpp_authentication *auth);
|
||||
struct wpabuf *
|
||||
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
const struct wpabuf *resp);
|
||||
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
|
||||
size_t len);
|
||||
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
|
||||
int dpp_check_attrs(const u8 *buf, size_t len);
|
||||
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
|
||||
const char * dpp_akm_str(enum dpp_akm akm);
|
||||
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
|
||||
size_t buflen);
|
||||
void dpp_configurator_free(struct dpp_configurator *conf);
|
||||
struct dpp_configurator *
|
||||
dpp_keygen_configurator(const char *curve, const u8 *privkey,
|
||||
size_t privkey_len);
|
||||
int dpp_configurator_own_config(struct dpp_authentication *auth,
|
||||
const char *curve, int ap);
|
||||
enum dpp_status_error
|
||||
dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
|
||||
const u8 *net_access_key, size_t net_access_key_len,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
const u8 *peer_connector, size_t peer_connector_len,
|
||||
os_time_t *expiry);
|
||||
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const char *identifier,
|
||||
const char *code);
|
||||
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const u8 *peer_mac,
|
||||
const char *identifier,
|
||||
const char *code,
|
||||
const u8 *buf, size_t len);
|
||||
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
const u8 *peer_mac,
|
||||
const u8 *buf, size_t len);
|
||||
struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
|
||||
const u8 *hdr,
|
||||
const u8 *buf, size_t len);
|
||||
int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
|
||||
const u8 *buf, size_t len);
|
||||
void dpp_pkex_free(struct dpp_pkex *pkex);
|
||||
|
||||
char * dpp_corrupt_connector_signature(const char *connector);
|
||||
|
||||
#endif /* DPP_H */
|
@ -75,7 +75,7 @@ gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
struct wpabuf *
|
||||
gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
|
||||
u16 comeback_delay, size_t size)
|
||||
{
|
||||
|
@ -14,6 +14,9 @@ struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
|
||||
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
|
||||
struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
|
||||
u16 comeback_delay, size_t size);
|
||||
struct wpabuf *
|
||||
gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
|
||||
u16 comeback_delay, size_t size);
|
||||
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
|
||||
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
|
||||
u16 comeback_delay, size_t size);
|
||||
|
487
contrib/wpa/src/common/gas_server.c
Normal file
487
contrib/wpa/src/common/gas_server.c
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/list.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "gas.h"
|
||||
#include "gas_server.h"
|
||||
|
||||
|
||||
#define MAX_ADV_PROTO_ID_LEN 10
|
||||
#define GAS_QUERY_TIMEOUT 10
|
||||
|
||||
struct gas_server_handler {
|
||||
struct dl_list list;
|
||||
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
|
||||
u8 adv_proto_id_len;
|
||||
struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len);
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
|
||||
void *ctx;
|
||||
struct gas_server *gas;
|
||||
};
|
||||
|
||||
struct gas_server_response {
|
||||
struct dl_list list;
|
||||
size_t offset;
|
||||
u8 frag_id;
|
||||
struct wpabuf *resp;
|
||||
int freq;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 dialog_token;
|
||||
struct gas_server_handler *handler;
|
||||
};
|
||||
|
||||
struct gas_server {
|
||||
struct dl_list handlers; /* struct gas_server_handler::list */
|
||||
struct dl_list responses; /* struct gas_server_response::list */
|
||||
void (*tx)(void *ctx, int freq, const u8 *da, struct wpabuf *resp,
|
||||
unsigned int wait_time);
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
static void gas_server_free_response(struct gas_server_response *response);
|
||||
|
||||
|
||||
static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
|
||||
{
|
||||
struct gas_server_response *response = eloop_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Response @%p timeout for " MACSTR
|
||||
" (dialog_token=%u freq=%d frag_id=%u sent=%lu/%lu) - drop pending data",
|
||||
response, MAC2STR(response->dst), response->dialog_token,
|
||||
response->freq, response->frag_id,
|
||||
(unsigned long) response->offset,
|
||||
(unsigned long) wpabuf_len(response->resp));
|
||||
response->handler->status_cb(response->handler->ctx,
|
||||
response->resp, 0);
|
||||
response->resp = NULL;
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
}
|
||||
|
||||
|
||||
static void gas_server_free_response(struct gas_server_response *response)
|
||||
{
|
||||
if (!response)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG, "DPP: Free GAS response @%p", response);
|
||||
eloop_cancel_timeout(gas_server_response_timeout, response, NULL);
|
||||
wpabuf_free(response->resp);
|
||||
os_free(response);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
const u8 *da, int freq, u8 dialog_token,
|
||||
struct wpabuf *query_resp)
|
||||
{
|
||||
size_t max_len = (freq > 56160) ? 928 : 1400;
|
||||
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
|
||||
size_t resp_frag_len;
|
||||
struct wpabuf *resp;
|
||||
u16 comeback_delay;
|
||||
struct gas_server_response *response;
|
||||
|
||||
if (!query_resp)
|
||||
return;
|
||||
|
||||
response = os_zalloc(sizeof(*response));
|
||||
if (!response) {
|
||||
wpabuf_free(query_resp);
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
|
||||
response->freq = freq;
|
||||
response->handler = handler;
|
||||
os_memcpy(response->dst, da, ETH_ALEN);
|
||||
response->dialog_token = dialog_token;
|
||||
if (hdr_len + wpabuf_len(query_resp) > max_len) {
|
||||
/* Need to use comeback to initiate fragmentation */
|
||||
comeback_delay = 1;
|
||||
resp_frag_len = 0;
|
||||
} else {
|
||||
/* Full response fits into the initial response */
|
||||
comeback_delay = 0;
|
||||
resp_frag_len = wpabuf_len(query_resp);
|
||||
}
|
||||
|
||||
resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS,
|
||||
comeback_delay,
|
||||
handler->adv_proto_id_len +
|
||||
resp_frag_len);
|
||||
if (!resp) {
|
||||
wpabuf_free(query_resp);
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
|
||||
wpabuf_put_u8(resp, 0x7f);
|
||||
/* Advertisement Protocol ID */
|
||||
wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
|
||||
|
||||
/* Query Response Length */
|
||||
wpabuf_put_le16(resp, resp_frag_len);
|
||||
if (!comeback_delay)
|
||||
wpabuf_put_buf(resp, query_resp);
|
||||
|
||||
if (comeback_delay) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Need to fragment query response");
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Full query response fits in the GAS Initial Response frame");
|
||||
}
|
||||
response->offset = resp_frag_len;
|
||||
response->resp = query_resp;
|
||||
dl_list_add(&gas->responses, &response->list);
|
||||
gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0);
|
||||
wpabuf_free(resp);
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT, 0,
|
||||
gas_server_response_timeout, response, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
const u8 *bssid, int freq, u8 dialog_token,
|
||||
const u8 *data, size_t len)
|
||||
{
|
||||
const u8 *pos, *end, *adv_proto, *query_req;
|
||||
u8 adv_proto_len;
|
||||
u16 query_req_len;
|
||||
struct gas_server_handler *handler;
|
||||
struct wpabuf *resp;
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
|
||||
data, len);
|
||||
pos = data;
|
||||
end = data + len;
|
||||
|
||||
if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No Advertisement Protocol element found");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
adv_proto_len = *pos++;
|
||||
if (end - pos < adv_proto_len || adv_proto_len < 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Truncated Advertisement Protocol element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
adv_proto = pos;
|
||||
pos += adv_proto_len;
|
||||
wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element",
|
||||
adv_proto, adv_proto_len);
|
||||
|
||||
if (end - pos < 2) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field");
|
||||
return -1;
|
||||
}
|
||||
query_req_len = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (end - pos < query_req_len) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field");
|
||||
return -1;
|
||||
}
|
||||
query_req = pos;
|
||||
pos += query_req_len;
|
||||
wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request",
|
||||
query_req, query_req_len);
|
||||
|
||||
if (pos < end) {
|
||||
wpa_hexdump(MSG_MSGDUMP,
|
||||
"GAS: Ignored extra data after Query Request field",
|
||||
pos, end - pos);
|
||||
}
|
||||
|
||||
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
|
||||
list) {
|
||||
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
|
||||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
|
||||
handler->adv_proto_id_len) != 0)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Calling handler for the requested Advertisement Protocol ID");
|
||||
resp = handler->req_cb(handler->ctx, sa, query_req,
|
||||
query_req_len);
|
||||
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
|
||||
resp);
|
||||
gas_server_send_resp(gas, handler, sa, freq, dialog_token,
|
||||
resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No registered handler for the requested Advertisement Protocol ID");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gas_server_handle_rx_comeback_req(struct gas_server_response *response)
|
||||
{
|
||||
struct gas_server_handler *handler = response->handler;
|
||||
struct gas_server *gas = handler->gas;
|
||||
size_t max_len = (response->freq > 56160) ? 928 : 1400;
|
||||
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
|
||||
size_t remaining, resp_frag_len;
|
||||
struct wpabuf *resp;
|
||||
|
||||
remaining = wpabuf_len(response->resp) - response->offset;
|
||||
if (hdr_len + remaining > max_len)
|
||||
resp_frag_len = max_len - hdr_len;
|
||||
else
|
||||
resp_frag_len = remaining;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Sending out %u/%u remaining Query Response octets",
|
||||
(unsigned int) resp_frag_len, (unsigned int) remaining);
|
||||
|
||||
resp = gas_build_comeback_resp(response->dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
response->frag_id++,
|
||||
resp_frag_len < remaining, 0,
|
||||
handler->adv_proto_id_len +
|
||||
resp_frag_len);
|
||||
if (!resp) {
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
|
||||
wpabuf_put_u8(resp, 0x7f);
|
||||
/* Advertisement Protocol ID */
|
||||
wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len);
|
||||
|
||||
/* Query Response Length */
|
||||
wpabuf_put_le16(resp, resp_frag_len);
|
||||
wpabuf_put_data(resp, wpabuf_head_u8(response->resp) + response->offset,
|
||||
resp_frag_len);
|
||||
|
||||
response->offset += resp_frag_len;
|
||||
|
||||
gas->tx(gas->ctx, response->freq, response->dst, resp,
|
||||
remaining > resp_frag_len ? 2000 : 0);
|
||||
wpabuf_free(resp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
const u8 *bssid, int freq, u8 dialog_token)
|
||||
{
|
||||
struct gas_server_response *response;
|
||||
|
||||
dl_list_for_each(response, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (response->dialog_token != dialog_token ||
|
||||
os_memcmp(sa, response->dst, ETH_ALEN) != 0)
|
||||
continue;
|
||||
gas_server_handle_rx_comeback_req(response);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: No pending GAS response for " MACSTR
|
||||
" (dialog token %u)", MAC2STR(sa), dialog_token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_rx - Indicate reception of a Public Action or Protected Dual frame
|
||||
* @gas: GAS query data from gas_server_init()
|
||||
* @da: Destination MAC address of the Action frame
|
||||
* @sa: Source MAC address of the Action frame
|
||||
* @bssid: BSSID of the Action frame
|
||||
* @categ: Category of the Action frame
|
||||
* @data: Payload of the Action frame
|
||||
* @len: Length of @data
|
||||
* @freq: Frequency (in MHz) on which the frame was received
|
||||
* Returns: 0 if the Public Action frame was a GAS request frame or -1 if not
|
||||
*/
|
||||
int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
const u8 *bssid, u8 categ, const u8 *data, size_t len,
|
||||
int freq)
|
||||
{
|
||||
u8 action, dialog_token;
|
||||
const u8 *pos, *end;
|
||||
|
||||
if (!gas || len < 2)
|
||||
return -1;
|
||||
|
||||
if (categ == WLAN_ACTION_PROTECTED_DUAL)
|
||||
return -1; /* Not supported for now */
|
||||
|
||||
pos = data;
|
||||
end = data + len;
|
||||
action = *pos++;
|
||||
dialog_token = *pos++;
|
||||
|
||||
if (action != WLAN_PA_GAS_INITIAL_REQ &&
|
||||
action != WLAN_PA_GAS_COMEBACK_REQ)
|
||||
return -1; /* Not a GAS request */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Received GAS %s Request frame DA=" MACSTR
|
||||
" SA=" MACSTR " BSSID=" MACSTR
|
||||
" freq=%d dialog_token=%u len=%u",
|
||||
action == WLAN_PA_GAS_INITIAL_REQ ? "Initial" : "Comeback",
|
||||
MAC2STR(da), MAC2STR(sa), MAC2STR(bssid), freq, dialog_token,
|
||||
(unsigned int) len);
|
||||
|
||||
if (action == WLAN_PA_GAS_INITIAL_REQ)
|
||||
return gas_server_rx_initial_req(gas, da, sa, bssid,
|
||||
freq, dialog_token,
|
||||
pos, end - pos);
|
||||
return gas_server_rx_comeback_req(gas, da, sa, bssid,
|
||||
freq, dialog_token);
|
||||
}
|
||||
|
||||
|
||||
static void gas_server_handle_tx_status(struct gas_server_response *response,
|
||||
int ack)
|
||||
{
|
||||
if (ack && response->offset < wpabuf_len(response->resp)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: More fragments remaining - keep pending entry");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ack)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No ACK received - drop pending entry");
|
||||
else
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Last fragment of the response sent out - drop pending entry");
|
||||
|
||||
response->handler->status_cb(response->handler->ctx,
|
||||
response->resp, ack);
|
||||
response->resp = NULL;
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
}
|
||||
|
||||
|
||||
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
size_t data_len, int ack)
|
||||
{
|
||||
const u8 *pos;
|
||||
u8 action, code, dialog_token;
|
||||
struct gas_server_response *response;
|
||||
|
||||
if (data_len < 24 + 3)
|
||||
return;
|
||||
pos = data + 24;
|
||||
action = *pos++;
|
||||
code = *pos++;
|
||||
dialog_token = *pos++;
|
||||
if (action != WLAN_ACTION_PUBLIC ||
|
||||
(code != WLAN_PA_GAS_INITIAL_RESP &&
|
||||
code != WLAN_PA_GAS_COMEBACK_RESP))
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status dst=" MACSTR
|
||||
" ack=%d %s dialog_token=%u",
|
||||
MAC2STR(dst), ack,
|
||||
code == WLAN_PA_GAS_INITIAL_RESP ? "initial" : "comeback",
|
||||
dialog_token);
|
||||
dl_list_for_each(response, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (response->dialog_token != dialog_token ||
|
||||
os_memcmp(dst, response->dst, ETH_ALEN) != 0)
|
||||
continue;
|
||||
gas_server_handle_tx_status(response, ack);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: No pending response matches TX status");
|
||||
}
|
||||
|
||||
|
||||
struct gas_server * gas_server_init(void *ctx,
|
||||
void (*tx)(void *ctx, int freq,
|
||||
const u8 *da,
|
||||
struct wpabuf *buf,
|
||||
unsigned int wait_time))
|
||||
{
|
||||
struct gas_server *gas;
|
||||
|
||||
gas = os_zalloc(sizeof(*gas));
|
||||
if (!gas)
|
||||
return NULL;
|
||||
gas->ctx = ctx;
|
||||
gas->tx = tx;
|
||||
dl_list_init(&gas->handlers);
|
||||
dl_list_init(&gas->responses);
|
||||
return gas;
|
||||
}
|
||||
|
||||
|
||||
void gas_server_deinit(struct gas_server *gas)
|
||||
{
|
||||
struct gas_server_handler *handler, *tmp;
|
||||
struct gas_server_response *response, *tmp_r;
|
||||
|
||||
if (!gas)
|
||||
return;
|
||||
|
||||
dl_list_for_each_safe(handler, tmp, &gas->handlers,
|
||||
struct gas_server_handler, list) {
|
||||
dl_list_del(&handler->list);
|
||||
os_free(handler);
|
||||
}
|
||||
|
||||
dl_list_for_each_safe(response, tmp_r, &gas->responses,
|
||||
struct gas_server_response, list) {
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
}
|
||||
|
||||
os_free(gas);
|
||||
}
|
||||
|
||||
|
||||
int gas_server_register(struct gas_server *gas,
|
||||
const u8 *adv_proto_id, u8 adv_proto_id_len,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx)
|
||||
{
|
||||
struct gas_server_handler *handler;
|
||||
|
||||
if (!gas || adv_proto_id_len > MAX_ADV_PROTO_ID_LEN)
|
||||
return -1;
|
||||
handler = os_zalloc(sizeof(*handler));
|
||||
if (!handler)
|
||||
return -1;
|
||||
|
||||
os_memcpy(handler->adv_proto_id, adv_proto_id, adv_proto_id_len);
|
||||
handler->adv_proto_id_len = adv_proto_id_len;
|
||||
handler->req_cb = req_cb;
|
||||
handler->status_cb = status_cb;
|
||||
handler->ctx = ctx;
|
||||
handler->gas = gas;
|
||||
dl_list_add(&gas->handlers, &handler->list);
|
||||
|
||||
return 0;
|
||||
}
|
44
contrib/wpa/src/common/gas_server.h
Normal file
44
contrib/wpa/src/common/gas_server.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef GAS_SERVER_H
|
||||
#define GAS_SERVER_H
|
||||
|
||||
#ifdef CONFIG_GAS_SERVER
|
||||
|
||||
struct gas_server;
|
||||
|
||||
struct gas_server * gas_server_init(void *ctx,
|
||||
void (*tx)(void *ctx, int freq,
|
||||
const u8 *da,
|
||||
struct wpabuf *buf,
|
||||
unsigned int wait_time));
|
||||
void gas_server_deinit(struct gas_server *gas);
|
||||
int gas_server_register(struct gas_server *gas,
|
||||
const u8 *adv_proto_id, u8 adv_proto_id_len,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx);
|
||||
int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
const u8 *bssid, u8 categ, const u8 *data, size_t len,
|
||||
int freq);
|
||||
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
size_t data_len, int ack);
|
||||
|
||||
#else /* CONFIG_GAS_SERVER */
|
||||
|
||||
static inline void gas_server_deinit(struct gas_server *gas)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GAS_SERVER */
|
||||
|
||||
#endif /* GAS_SERVER_H */
|
@ -89,7 +89,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
|
||||
{
|
||||
int ok, j, first;
|
||||
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
|
||||
149, 157, 184, 192 };
|
||||
149, 157, 165, 184, 192 };
|
||||
size_t k;
|
||||
|
||||
if (pri_chan == sec_chan || !sec_chan)
|
||||
@ -388,8 +388,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
/* fall through */
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
data->bandwidth = 80;
|
||||
if ((vht_oper_chwidth == 1 && center_segment1) ||
|
||||
(vht_oper_chwidth == 3 && !center_segment1) ||
|
||||
if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
|
||||
center_segment1) ||
|
||||
(vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
|
||||
!center_segment1) ||
|
||||
!sec_channel_offset)
|
||||
return -1;
|
||||
if (!center_segment0) {
|
||||
@ -453,3 +455,101 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
|
||||
int disabled)
|
||||
{
|
||||
/* Masking these out disables HT40 */
|
||||
le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
|
||||
HT_CAP_INFO_SHORT_GI40MHZ);
|
||||
|
||||
if (disabled)
|
||||
htcaps->ht_capabilities_info &= ~msk;
|
||||
else
|
||||
htcaps->ht_capabilities_info |= msk;
|
||||
}
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
int ieee80211ac_cap_check(u32 hw, u32 conf)
|
||||
{
|
||||
#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_MAX(VHT_CAP_SUPP_CHAN_WIDTH_MASK);
|
||||
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 */
|
||||
|
@ -35,5 +35,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
int vht_enabled, int sec_channel_offset,
|
||||
int vht_oper_chwidth, int center_segment0,
|
||||
int center_segment1, u32 vht_caps);
|
||||
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
|
||||
int disabled);
|
||||
int ieee80211ac_cap_check(u32 hw, u32 conf);
|
||||
|
||||
#endif /* HW_FEATURES_COMMON_H */
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "common.h"
|
||||
#include "defs.h"
|
||||
#include "wpa_common.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "qca-vendor.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "ieee802_11_common.h"
|
||||
@ -120,6 +121,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
elems->mbo = pos;
|
||||
elems->mbo_len = elen;
|
||||
break;
|
||||
case HS20_ROAMING_CONS_SEL_OUI_TYPE:
|
||||
/* Hotspot 2.0 Roaming Consortium Selection */
|
||||
elems->roaming_cons_sel = pos;
|
||||
elems->roaming_cons_sel_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
|
||||
"information element ignored "
|
||||
@ -179,6 +185,100 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
}
|
||||
|
||||
|
||||
static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors)
|
||||
{
|
||||
u8 ext_id;
|
||||
|
||||
if (elen < 1) {
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"short information element (Ext)");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ext_id = *pos++;
|
||||
elen--;
|
||||
|
||||
switch (ext_id) {
|
||||
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
|
||||
if (elen != 1)
|
||||
break;
|
||||
elems->assoc_delay_info = pos;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_REQ_PARAMS:
|
||||
if (elen < 3)
|
||||
break;
|
||||
elems->fils_req_params = pos;
|
||||
elems->fils_req_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_KEY_CONFIRM:
|
||||
elems->fils_key_confirm = pos;
|
||||
elems->fils_key_confirm_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_SESSION:
|
||||
if (elen != FILS_SESSION_LEN)
|
||||
break;
|
||||
elems->fils_session = pos;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_HLP_CONTAINER:
|
||||
if (elen < 2 * ETH_ALEN)
|
||||
break;
|
||||
elems->fils_hlp = pos;
|
||||
elems->fils_hlp_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
|
||||
if (elen < 1)
|
||||
break;
|
||||
elems->fils_ip_addr_assign = pos;
|
||||
elems->fils_ip_addr_assign_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_KEY_DELIVERY:
|
||||
if (elen < WPA_KEY_RSC_LEN)
|
||||
break;
|
||||
elems->key_delivery = pos;
|
||||
elems->key_delivery_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_WRAPPED_DATA:
|
||||
elems->fils_wrapped_data = pos;
|
||||
elems->fils_wrapped_data_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
|
||||
if (elen < 1)
|
||||
break;
|
||||
elems->fils_pk = pos;
|
||||
elems->fils_pk_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_NONCE:
|
||||
if (elen != FILS_NONCE_LEN)
|
||||
break;
|
||||
elems->fils_nonce = pos;
|
||||
break;
|
||||
case WLAN_EID_EXT_OWE_DH_PARAM:
|
||||
if (elen < 2)
|
||||
break;
|
||||
elems->owe_dh = pos;
|
||||
elems->owe_dh_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
|
||||
elems->password_id = pos;
|
||||
elems->password_id_len = elen;
|
||||
break;
|
||||
default:
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
|
||||
ext_id, (unsigned int) elen);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_11_parse_elems - Parse information elements in management frames
|
||||
* @start: Pointer to the start of IEs
|
||||
@ -262,6 +362,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->rsn_ie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PWR_CAPABILITY:
|
||||
if (elen < 2)
|
||||
break;
|
||||
elems->power_capab = pos;
|
||||
elems->power_capab_len = elen;
|
||||
break;
|
||||
case WLAN_EID_SUPPORTED_CHANNELS:
|
||||
elems->supp_channels = pos;
|
||||
@ -379,6 +483,35 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->rrm_enabled = pos;
|
||||
elems->rrm_enabled_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CAG_NUMBER:
|
||||
elems->cag_number = pos;
|
||||
elems->cag_number_len = elen;
|
||||
break;
|
||||
case WLAN_EID_AP_CSN:
|
||||
if (elen < 1)
|
||||
break;
|
||||
elems->ap_csn = pos;
|
||||
break;
|
||||
case WLAN_EID_FILS_INDICATION:
|
||||
if (elen < 2)
|
||||
break;
|
||||
elems->fils_indic = pos;
|
||||
elems->fils_indic_len = elen;
|
||||
break;
|
||||
case WLAN_EID_DILS:
|
||||
if (elen < 2)
|
||||
break;
|
||||
elems->dils = pos;
|
||||
elems->dils_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FRAGMENT:
|
||||
/* TODO */
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (ieee802_11_parse_extension(pos, elen, elems,
|
||||
show_errors))
|
||||
unknown++;
|
||||
break;
|
||||
default:
|
||||
unknown++;
|
||||
if (!show_errors)
|
||||
@ -681,6 +814,25 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 52..64 */
|
||||
if (freq >= 5260 && freq <= 5320) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (vht_opclass)
|
||||
*op_class = vht_opclass;
|
||||
else if (sec_channel == 1)
|
||||
*op_class = 119;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 120;
|
||||
else
|
||||
*op_class = 118;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..169 */
|
||||
if (freq >= 5745 && freq <= 5845) {
|
||||
if ((freq - 5000) % 5)
|
||||
@ -981,7 +1133,7 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
|
||||
return -1;
|
||||
return 5000 + 5 * chan;
|
||||
case 129: /* center freqs 50, 114; 160 MHz */
|
||||
if (chan < 50 || chan > 114)
|
||||
if (chan < 36 || chan > 128)
|
||||
return -1;
|
||||
return 5000 + 5 * chan;
|
||||
case 180: /* 60 GHz band, channels 1..4 */
|
||||
@ -1031,10 +1183,24 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_is_dfs(int freq)
|
||||
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
|
||||
u16 num_modes)
|
||||
{
|
||||
/* TODO: this could be more accurate to better cover all domains */
|
||||
return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
|
||||
int i, j;
|
||||
|
||||
if (!modes || !num_modes)
|
||||
return (freq >= 5260 && freq <= 5320) ||
|
||||
(freq >= 5500 && freq <= 5700);
|
||||
|
||||
for (i = 0; i < num_modes; i++) {
|
||||
for (j = 0; j < modes[i].num_channels; j++) {
|
||||
if (modes[i].channels[j].freq == freq &&
|
||||
(modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1295,6 +1461,40 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_ie_ext - Fetch a specified extended information element from IEs buffer
|
||||
* @ies: Information elements buffer
|
||||
* @len: Information elements buffer length
|
||||
* @ext: Information element extension identifier (WLAN_EID_EXT_*)
|
||||
* Returns: Pointer to the information element (id field) or %NULL if not found
|
||||
*
|
||||
* This function returns the first matching information element in the IEs
|
||||
* buffer or %NULL in case the element is not found.
|
||||
*/
|
||||
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
|
||||
{
|
||||
const u8 *end;
|
||||
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
end = ies + len;
|
||||
|
||||
while (end - ies > 1) {
|
||||
if (2 + ies[1] > end - ies)
|
||||
break;
|
||||
|
||||
if (ies[0] == WLAN_EID_EXTENSION && ies[1] >= 1 &&
|
||||
ies[2] == ext)
|
||||
return ies;
|
||||
|
||||
ies += 2 + ies[1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||
{
|
||||
/*
|
||||
@ -1317,3 +1517,250 @@ size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||
|
||||
return 6 + attr_len;
|
||||
}
|
||||
|
||||
|
||||
static const struct country_op_class us_op_class[] = {
|
||||
{ 1, 115 },
|
||||
{ 2, 118 },
|
||||
{ 3, 124 },
|
||||
{ 4, 121 },
|
||||
{ 5, 125 },
|
||||
{ 12, 81 },
|
||||
{ 22, 116 },
|
||||
{ 23, 119 },
|
||||
{ 24, 122 },
|
||||
{ 25, 126 },
|
||||
{ 26, 126 },
|
||||
{ 27, 117 },
|
||||
{ 28, 120 },
|
||||
{ 29, 123 },
|
||||
{ 30, 127 },
|
||||
{ 31, 127 },
|
||||
{ 32, 83 },
|
||||
{ 33, 84 },
|
||||
{ 34, 180 },
|
||||
};
|
||||
|
||||
static const struct country_op_class eu_op_class[] = {
|
||||
{ 1, 115 },
|
||||
{ 2, 118 },
|
||||
{ 3, 121 },
|
||||
{ 4, 81 },
|
||||
{ 5, 116 },
|
||||
{ 6, 119 },
|
||||
{ 7, 122 },
|
||||
{ 8, 117 },
|
||||
{ 9, 120 },
|
||||
{ 10, 123 },
|
||||
{ 11, 83 },
|
||||
{ 12, 84 },
|
||||
{ 17, 125 },
|
||||
{ 18, 180 },
|
||||
};
|
||||
|
||||
static const struct country_op_class jp_op_class[] = {
|
||||
{ 1, 115 },
|
||||
{ 30, 81 },
|
||||
{ 31, 82 },
|
||||
{ 32, 118 },
|
||||
{ 33, 118 },
|
||||
{ 34, 121 },
|
||||
{ 35, 121 },
|
||||
{ 36, 116 },
|
||||
{ 37, 119 },
|
||||
{ 38, 119 },
|
||||
{ 39, 122 },
|
||||
{ 40, 122 },
|
||||
{ 41, 117 },
|
||||
{ 42, 120 },
|
||||
{ 43, 120 },
|
||||
{ 44, 123 },
|
||||
{ 45, 123 },
|
||||
{ 56, 83 },
|
||||
{ 57, 84 },
|
||||
{ 58, 121 },
|
||||
{ 59, 180 },
|
||||
};
|
||||
|
||||
static const struct country_op_class cn_op_class[] = {
|
||||
{ 1, 115 },
|
||||
{ 2, 118 },
|
||||
{ 3, 125 },
|
||||
{ 4, 116 },
|
||||
{ 5, 119 },
|
||||
{ 6, 126 },
|
||||
{ 7, 81 },
|
||||
{ 8, 83 },
|
||||
{ 9, 84 },
|
||||
};
|
||||
|
||||
static u8
|
||||
global_op_class_from_country_array(u8 op_class, size_t array_size,
|
||||
const struct country_op_class *country_array)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < array_size; i++) {
|
||||
if (country_array[i].country_op_class == op_class)
|
||||
return country_array[i].global_op_class;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u8 country_to_global_op_class(const char *country, u8 op_class)
|
||||
{
|
||||
const struct country_op_class *country_array;
|
||||
size_t size;
|
||||
u8 g_op_class;
|
||||
|
||||
if (country_match(us_op_class_cc, country)) {
|
||||
country_array = us_op_class;
|
||||
size = ARRAY_SIZE(us_op_class);
|
||||
} else if (country_match(eu_op_class_cc, country)) {
|
||||
country_array = eu_op_class;
|
||||
size = ARRAY_SIZE(eu_op_class);
|
||||
} else if (country_match(jp_op_class_cc, country)) {
|
||||
country_array = jp_op_class;
|
||||
size = ARRAY_SIZE(jp_op_class);
|
||||
} else if (country_match(cn_op_class_cc, country)) {
|
||||
country_array = cn_op_class;
|
||||
size = ARRAY_SIZE(cn_op_class);
|
||||
} else {
|
||||
/*
|
||||
* Countries that do not match any of the above countries use
|
||||
* global operating classes
|
||||
*/
|
||||
return op_class;
|
||||
}
|
||||
|
||||
g_op_class = global_op_class_from_country_array(op_class, size,
|
||||
country_array);
|
||||
|
||||
/*
|
||||
* If the given operating class did not match any of the country's
|
||||
* operating classes, assume that global operating class is used.
|
||||
*/
|
||||
return g_op_class ? g_op_class : op_class;
|
||||
}
|
||||
|
||||
|
||||
const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
|
||||
{
|
||||
const struct oper_class_map *op;
|
||||
|
||||
if (country)
|
||||
op_class = country_to_global_op_class(country, op_class);
|
||||
|
||||
op = &global_op_class[0];
|
||||
while (op->op_class && op->op_class != op_class)
|
||||
op++;
|
||||
|
||||
if (!op->op_class)
|
||||
return NULL;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len)
|
||||
{
|
||||
u8 *nei_pos = nei_rep;
|
||||
const char *end;
|
||||
|
||||
/*
|
||||
* BSS Transition Candidate List Entries - Neighbor Report elements
|
||||
* neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
|
||||
* <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
|
||||
*/
|
||||
while (pos) {
|
||||
u8 *nei_start;
|
||||
long int val;
|
||||
char *endptr, *tmp;
|
||||
|
||||
pos = os_strstr(pos, " neighbor=");
|
||||
if (!pos)
|
||||
break;
|
||||
if (nei_pos + 15 > nei_rep + nei_rep_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Not enough room for additional neighbor");
|
||||
return -1;
|
||||
}
|
||||
pos += 10;
|
||||
|
||||
nei_start = nei_pos;
|
||||
*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
|
||||
nei_pos++; /* length to be filled in */
|
||||
|
||||
if (hwaddr_aton(pos, nei_pos)) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid BSSID");
|
||||
return -1;
|
||||
}
|
||||
nei_pos += ETH_ALEN;
|
||||
pos += 17;
|
||||
if (*pos != ',') {
|
||||
wpa_printf(MSG_DEBUG, "Missing BSSID Information");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
val = strtol(pos, &endptr, 0);
|
||||
WPA_PUT_LE32(nei_pos, val);
|
||||
nei_pos += 4;
|
||||
if (*endptr != ',') {
|
||||
wpa_printf(MSG_DEBUG, "Missing Operating Class");
|
||||
return -1;
|
||||
}
|
||||
pos = endptr + 1;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* Operating Class */
|
||||
pos = os_strchr(pos, ',');
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Missing Channel Number");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* Channel Number */
|
||||
pos = os_strchr(pos, ',');
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Missing PHY Type");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* PHY Type */
|
||||
end = os_strchr(pos, ' ');
|
||||
tmp = os_strchr(pos, ',');
|
||||
if (tmp && (!end || tmp < end)) {
|
||||
/* Optional Subelements (hexdump) */
|
||||
size_t len;
|
||||
|
||||
pos = tmp + 1;
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Not enough room for neighbor subelements");
|
||||
return -1;
|
||||
}
|
||||
if (len & 0x01 ||
|
||||
hexstr2bin(pos, nei_pos, len / 2) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Invalid neighbor subelement info");
|
||||
return -1;
|
||||
}
|
||||
nei_pos += len / 2;
|
||||
pos = end;
|
||||
}
|
||||
|
||||
nei_start[1] = nei_pos - nei_start - 2;
|
||||
}
|
||||
|
||||
return nei_pos - nei_rep;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
struct hostapd_hw_modes;
|
||||
|
||||
#define MAX_NOF_MB_IES_SUPPORTED 5
|
||||
|
||||
struct mb_ies_info {
|
||||
@ -64,6 +66,24 @@ struct ieee802_11_elems {
|
||||
const u8 *pref_freq_list;
|
||||
const u8 *supp_op_classes;
|
||||
const u8 *rrm_enabled;
|
||||
const u8 *cag_number;
|
||||
const u8 *ap_csn;
|
||||
const u8 *fils_indic;
|
||||
const u8 *dils;
|
||||
const u8 *assoc_delay_info;
|
||||
const u8 *fils_req_params;
|
||||
const u8 *fils_key_confirm;
|
||||
const u8 *fils_session;
|
||||
const u8 *fils_hlp;
|
||||
const u8 *fils_ip_addr_assign;
|
||||
const u8 *key_delivery;
|
||||
const u8 *fils_wrapped_data;
|
||||
const u8 *fils_pk;
|
||||
const u8 *fils_nonce;
|
||||
const u8 *owe_dh;
|
||||
const u8 *power_capab;
|
||||
const u8 *roaming_cons_sel;
|
||||
const u8 *password_id;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
@ -96,6 +116,20 @@ struct ieee802_11_elems {
|
||||
u8 pref_freq_list_len;
|
||||
u8 supp_op_classes_len;
|
||||
u8 rrm_enabled_len;
|
||||
u8 cag_number_len;
|
||||
u8 fils_indic_len;
|
||||
u8 dils_len;
|
||||
u8 fils_req_params_len;
|
||||
u8 fils_key_confirm_len;
|
||||
u8 fils_hlp_len;
|
||||
u8 fils_ip_addr_assign_len;
|
||||
u8 key_delivery_len;
|
||||
u8 fils_wrapped_data_len;
|
||||
u8 fils_pk_len;
|
||||
u8 owe_dh_len;
|
||||
u8 power_capab_len;
|
||||
u8 roaming_cons_sel_len;
|
||||
u8 password_id_len;
|
||||
|
||||
struct mb_ies_info mb_ies;
|
||||
};
|
||||
@ -126,7 +160,8 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
|
||||
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel);
|
||||
int ieee80211_is_dfs(int freq);
|
||||
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
|
||||
u16 num_modes);
|
||||
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
|
||||
|
||||
int supp_rates_11b_only(struct ieee802_11_elems *elems);
|
||||
@ -150,7 +185,20 @@ extern const struct oper_class_map global_op_class[];
|
||||
extern size_t global_op_class_size;
|
||||
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
||||
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
||||
|
||||
struct country_op_class {
|
||||
u8 country_op_class;
|
||||
u8 global_op_class;
|
||||
};
|
||||
|
||||
u8 country_to_global_op_class(const char *country, u8 op_class);
|
||||
|
||||
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len);
|
||||
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user