wpa: Import wpa 2.11

This commit is contained in:
Cy Schubert
2024-07-21 06:14:24 -07:00
parent df0c787c3e
commit 950d2f4337
387 changed files with 63686 additions and 36064 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ without moderation. You can subscribe to the list at this address:
http://lists.infradead.org/mailman/listinfo/hostap
The message should contain an inlined patch against the current
development branch (i.e., the master branch of
development branch (i.e., the main branch of
git://w1.fi/hostap.git). Please make sure the software you use for
sending the patch does not corrupt whitespace. If that cannot be fixed
for some reason, it is better to include an attached version of the
+1 -1
View File
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
-5
View File
@@ -1,5 +0,0 @@
.config
hostapd
hostapd_cli
hlr_auc_gw
nt_password_hash
-1155
View File
File diff suppressed because it is too large Load Diff
-1321
View File
File diff suppressed because it is too large Load Diff
-1378
View File
File diff suppressed because it is too large Load Diff
-354
View File
@@ -1,354 +0,0 @@
hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
advertisement clause removed).
If you are submitting changes to the project, please see CONTRIBUTIONS
file for more instructions.
License
-------
This software may be distributed, used, and modified under the terms of
BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Introduction
============
Originally, hostapd was an optional user space component for Host AP
driver. It adds more features to the basic IEEE 802.11 management
included in the kernel driver: using external RADIUS authentication
server for MAC address based access control, IEEE 802.1X Authenticator
and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
Authenticator and dynamic TKIP/CCMP keying.
The current version includes support for other drivers, an integrated
EAP server (i.e., allow full authentication without requiring
an external RADIUS authentication server), and RADIUS authentication
server for EAP authentication.
Requirements
------------
Current hardware/software requirements:
- drivers:
Host AP driver for Prism2/2.5/3.
(http://w1.fi/hostap-driver.html)
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
mac80211-based drivers that support AP mode (with driver=nl80211).
This includes drivers for Atheros (ath9k) and Broadcom (b43)
chipsets.
Any wired Ethernet driver for wired IEEE 802.1X authentication
(experimental code)
FreeBSD -current
BSD net80211 layer (e.g., Atheros driver)
Build configuration
-------------------
In order to be able to build hostapd, you will need to create a build
time configuration file, .config that selects which optional
components are included. See defconfig file for example configuration
and list of available options.
IEEE 802.1X
===========
IEEE Std 802.1X-2001 is a standard for port-based network access
control. In case of IEEE 802.11 networks, a "virtual port" is used
between each associated station and the AP. IEEE 802.11 specifies
minimal authentication mechanism for stations, whereas IEEE 802.1X
introduces a extensible mechanism for authenticating and authorizing
users.
IEEE 802.1X uses elements called Supplicant, Authenticator, Port
Access Entity, and Authentication Server. Supplicant is a component in
a station and it performs the authentication with the Authentication
Server. An access point includes an Authenticator that relays the packets
between a Supplicant and an Authentication Server. In addition, it has a
Port Access Entity (PAE) with Authenticator functionality for
controlling the virtual port authorization, i.e., whether to accept
packets from or to the station.
IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
between a Supplicant and an Authenticator are sent using EAP over LAN
(EAPOL) and the Authenticator relays these frames to the Authentication
Server (and similarly, relays the messages from the Authentication
Server to the Supplicant). The Authentication Server can be colocated with the
Authenticator, in which case there is no need for additional protocol
for EAP frame transmission. However, a more common configuration is to
use an external Authentication Server and encapsulate EAP frame in the
frames used by that server. RADIUS is suitable for this, but IEEE
802.1X would also allow other mechanisms.
Host AP driver includes PAE functionality in the kernel driver. It
is a relatively simple mechanism for denying normal frames going to
or coming from an unauthorized port. PAE allows IEEE 802.1X related
frames to be passed between the Supplicant and the Authenticator even
on an unauthorized port.
User space daemon, hostapd, includes Authenticator functionality. It
receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
device that is also used with IEEE 802.11 management frames. The
frames to the Supplicant are sent using the same device.
The normal configuration of the Authenticator would use an external
Authentication Server. hostapd supports RADIUS encapsulation of EAP
packets, so the Authentication Server should be a RADIUS server, like
FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
relays the frames between the Supplicant and the Authentication
Server. It also controls the PAE functionality in the kernel driver by
controlling virtual port authorization, i.e., station-AP
connection, based on the IEEE 802.1X state.
When a station would like to use the services of an access point, it
will first perform IEEE 802.11 authentication. This is normally done
with open systems authentication, so there is no security. After
this, IEEE 802.11 association is performed. If IEEE 802.1X is
configured to be used, the virtual port for the station is set in
Unauthorized state and only IEEE 802.1X frames are accepted at this
point. The Authenticator will then ask the Supplicant to authenticate
with the Authentication Server. After this is completed successfully,
the virtual port is set to Authorized state and frames from and to the
station are accepted.
Host AP configuration for IEEE 802.1X
-------------------------------------
The user space daemon has its own configuration file that can be used to
define AP options. Distribution package contains an example
configuration file (hostapd/hostapd.conf) that can be used as a basis
for configuration. It includes examples of all supported configuration
options and short description of each option. hostapd should be started
with full path to the configuration file as the command line argument,
e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
LAN card, you can use one hostapd process for multiple interfaces by
giving a list of configuration files (one per interface) in the command
line.
hostapd includes a minimal co-located IEEE 802.1X server which can be
used to test IEEE 802.1X authentication. However, it should not be
used in normal use since it does not provide any security. This can be
configured by setting ieee8021x and minimal_eap options in the
configuration file.
An external Authentication Server (RADIUS) is configured with
auth_server_{addr,port,shared_secret} options. In addition,
ieee8021x and own_ip_addr must be set for this mode. With such
configuration, the co-located Authentication Server is not used and EAP
frames will be relayed using EAPOL between the Supplicant and the
Authenticator and RADIUS encapsulation between the Authenticator and
the Authentication Server. Other than this, the functionality is similar
to the case with the co-located Authentication Server.
Authentication Server
---------------------
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.
Automatic WEP key configuration
-------------------------------
EAP/TLS generates a session key that can be used to send WEP keys from
an AP to authenticated stations. The Authenticator in hostapd can be
configured to automatically select a random default/broadcast key
(shared by all authenticated stations) with wep_key_len_broadcast
option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
wep_key_len_unicast option can be used to configure individual unicast
keys for stations. This requires support for individual keys in the
station driver.
WEP keys can be automatically updated by configuring rekeying. This
will improve security of the network since same WEP key will only be
used for a limited period of time. wep_rekey_period option sets the
interval for rekeying in seconds.
WPA/WPA2
========
Features
--------
Supported WPA/IEEE 802.11i features:
- WPA-PSK ("WPA-Personal")
- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
- key management for CCMP, TKIP, WEP104, WEP40
- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
WPA
---
The original security mechanism of IEEE 802.11 standard was not
designed to be strong and has proved to be insufficient for most
networks that require some kind of security. Task group I (Security)
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
to address the flaws of the base standard and has in practice
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
802.11 standard was approved in June 2004 and this amendment 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.
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
24-bit initialization vector (IV), and CRC32 to protect against packet
forgery. All these choices have proven to be insufficient: key space is
too small against current attacks, RC4 key scheduling is insufficient
(beginning of the pseudorandom stream should be skipped), IV space is
too small and IV reuse makes attacks easier, there is no replay
protection, and non-keyed authentication does not protect against bit
flipping packet data.
WPA is an intermediate solution for the security issues. It uses
Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
compromise on strong security and possibility to use existing
hardware. It still uses RC4 for the encryption like WEP, but with
per-packet RC4 keys. In addition, it implements replay protection,
keyed packet authentication mechanism (Michael MIC).
Keys can be managed using two different mechanisms. WPA can either use
an external authentication server (e.g., RADIUS) and EAP just like
IEEE 802.1X is using or pre-shared keys without need for additional
servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
respectively. Both mechanisms will generate a master session key for
the Authenticator (AP) and Supplicant (client station).
WPA implements a new key handshake (4-Way Handshake and Group Key
Handshake) for generating and exchanging data encryption keys between
the Authenticator and Supplicant. This handshake is also used to
verify that both Authenticator and Supplicant know the master session
key. These handshakes are identical regardless of the selected key
management mechanism (only the method for generating master session
key changes).
IEEE 802.11i / WPA2
-------------------
The design for parts of IEEE 802.11i that were not included in WPA has
finished (May 2004) and this amendment to IEEE 802.11 was approved in
June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
version of WPA called WPA2. This includes, e.g., support for more
robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
to replace TKIP and optimizations for handoff (reduced number of
messages in initial key handshake, pre-authentication, and PMKSA caching).
Some wireless LAN vendors are already providing support for CCMP in
their WPA products. There is no "official" interoperability
certification for CCMP and/or mixed modes using both TKIP and CCMP, so
some interoperability issues can be expected even though many
combinations seem to be working with equipment from different vendors.
Testing for WPA2 is likely to start during the second half of 2004.
hostapd configuration for WPA/WPA2
----------------------------------
TODO
# Enable WPA. Setting this variable configures the AP to require WPA (either
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
# RADIUS authentication server must be configured, and WPA-EAP must be included
# in wpa_key_mgmt.
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
# and/or WPA2 (full IEEE 802.11i/RSN):
# bit0 = WPA
# bit1 = IEEE 802.11i/RSN (WPA2)
#wpa=1
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
#wpa_passphrase=secret passphrase
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space.
#wpa_key_mgmt=WPA-PSK WPA-EAP
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
# (unicast packets). This is a space separated list of algorithms:
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
# is automatically selected based on this configuration. If only CCMP is
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
# TKIP will be used as the group cipher.
#wpa_pairwise=TKIP CCMP
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
# seconds.
#wpa_group_rekey=600
# Time interval for rekeying GMK (master key used internally to generate GTKs
# (in seconds).
#wpa_gmk_rekey=86400
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
# authentication and key handshake before actually associating with a new AP.
#rsn_preauth=1
#
# Space separated list of interfaces from which pre-authentication frames are
# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
# interface that are used for connections to other APs. This could include
# wired interfaces and WDS links. The normal wireless data interface towards
# associated stations (e.g., wlan0) should not be added, since
# pre-authentication is only used with APs other than the currently associated
# one.
#rsn_preauth_interfaces=eth0
-160
View File
@@ -1,160 +0,0 @@
hostapd, wpa_supplicant and the Multi-AP Specification
======================================================
This document describes how hostapd and wpa_supplicant can be configured to
support the Multi-AP Specification.
Introduction to Multi-AP
------------------------
The Wi-Fi Alliance Multi-AP Specification is the technical specification for
Wi-Fi CERTIFIED EasyMesh(TM) [1], the Wi-Fi Alliance® certification program for
Multi-AP. It defines control protocols between Wi-Fi® access points (APs) to
join them into a network with centralized control and operation. It is targeted
only at routers (repeaters, gateways, ...), not at clients. Clients are not
involved at all in the protocols.
Most of the Multi-AP specification falls outside of the scope of
hostapd/wpa_supplicant. hostapd/wpa_supplicant is only involved for the items
summarized below. The rest of the protocol must be implemented by a separate
daemon, e.g., prplMesh [2]. That daemon also needs to communicate with hostapd,
e.g., to get a list of associated clients, but this can be done using the normal
hostapd interfaces.
hostapd/wpa_supplicant needs to be configured specifically to support:
- the WPS onboarding process;
- configuring backhaul links.
The text below refers to "Multi-AP Specification v1.0" [3].
Fronthaul and backhaul links
----------------------------
In a Multi-AP network, the central controller can configure the BSSs on the
devices that are joined into the network. These are called fronthaul BSSs.
From the point of view of hostapd, there is nothing special about these
fronthaul BSSs.
In addition to fronthaul BSSs, the controller can also configure backhaul
links. A backhaul link is a link between two access point devices, giving
internet access to access point devices that don't have a wired link. The
Multi-AP specification doesn't dictate this, but typically the backhaul link
will be bridged into a LAN together with (one of) the fronthaul BSS(s) and the
wired Ethernet ports.
A backhaul link must be treated specially by hostapd and wpa_supplicant. One
side of the backhaul link is configured through the Multi-AP protocol as the
"backhaul STA", i.e., the client side of the link. A backhaul STA is like any
station and is handled appropriately by wpa_supplicant, but two additional
features are required. It must send an additional information element in each
(Re)Association Request frame ([3], section 5.2, paragraph 4). In addition, it
must use 4-address mode for all frames sent over this link ([3], section 14).
Therefore, wpa_supplicant must be configured explicitly as the backhaul STA
role, by setting 'multi_ap_backhaul_sta=1' in the network configuration block
or when configuring the network profile through the control interface. When
'multi_ap_backhaul_sta=1', wpa_supplicant includes the Multi-AP IE in
(Re)Association Request frame and verifies that it is included in the
(Re)Association Response frame. If it is not, association fails. If it is,
wpa_supplicant sets 4-address mode for this interface through a driver
callback.
The AP side of the backhaul link is called a "backhaul BSS". Such a BSS must
be handled specially by hostapd, because it must add an additional information
element in each (Re)Association Response frame, but only to stations that have
identified themselves as backhaul stations ([3], section 5.2, paragraph 5-6).
This is important because it is possible to use the same BSS and SSID for
fronthaul and backhaul at the same time. The additional information element must
only be used for frames sent to a backhaul STA, not to a normal STA. Also,
frames sent to a backhaul STA must use 4-address mode, while frames sent to a
normal STA (fronthaul, when it's a fronthaul and backhaul BSS) must use
3-address mode.
A BSS is configured in Multi-AP mode in hostapd by setting the 'multi_ap'
configuration option to 1 (backhaul BSS), 2 (fronthaul BSS), or 3
(simultaneous backhaul and fronthaul BSS). If this option is set, hostapd
parses the Multi-AP information element in the Association Request frame. If the
station is a backhaul STA and the BSS is configured as a backhaul BSS,
hostapd sets up 4-address mode. Since there may be multiple stations connected
simultaneously, and each of them has a different RA (receiver address), a VLAN
is created for each backhaul STA and it is automatically added to a bridge.
This is the same behavior as for WDS, and the relevant option ('bridge' or
'wds_bridge') applies here as well.
If 'multi_ap' is 1 (backhaul BSS only), any station that tries to associate
without the Multi-AP information element will be denied.
If 'multi_ap' is 2 (fronthaul BSS only), any station that tries to associate
with the Multi-AP information element will be denied. That is also the only
difference with 'multi_ap' set to 0: in the latter case, the Multi-AP
information element is simply ignored.
In summary, this is the end-to-end behavior for a backhaul BSS (i.e.,
multi_ap_backhaul_sta=1 in wpa_supplicant on STA, and multi_ap=1 or 3 in
hostapd on AP). Note that point 1 means that hostapd must not be configured
with WPS support on the backhaul BSS (multi_ap=1). hostapd does not check for
that.
1. Backhaul BSS beacons do not advertise WPS support (other than that, nothing
Multi-AP specific).
2. STA sends Authentication frame (nothing Multi-AP specific).
3. AP sends Authentication frame (nothing Multi-AP specific).
4. STA sends Association Request frame with Multi-AP IE.
5. AP sends Association Response frame with Multi-AP IE.
6. STA and AP both use 4-address mode for Data frames.
WPS support
-----------
WPS requires more special handling. WPS must only be advertised on fronthaul
BSSs, not on backhaul BSSs, so WPS should not be enabled on a backhaul-only
BSS in hostapd.conf. The WPS configuration purely works on the fronthaul BSS.
When a WPS M1 message has an additional subelement that indicates a request for
a Multi-AP backhaul link, hostapd must not respond with the normal fronthaul
BSS credentials; instead, it should respond with the (potentially different)
backhaul BSS credentials.
To support this, hostapd has the 'multi_ap_backhaul_ssid',
'multi_ap_backhaul_wpa_psk' and 'multi_ap_backhaul_wpa_passphrase' options.
When these are set on an BSS with WPS, they are used instead of the normal
credentials when hostapd receives a WPS M1 message with the Multi-AP IE. Only
WPA2-Personal is supported in the Multi-AP specification, so there is no need
to specify authentication or encryption options. For the backhaul credentials,
per-device PSK is not supported.
If the BSS is a simultaneous backhaul and fronthaul BSS, there is no need to
specify the backhaul credentials, since the backhaul and fronthaul credentials
are identical.
To enable the Multi-AP backhaul STA feature when it performs WPS, a new
parameter has been introduced to the WPS_PBC control interface call. When this
"multi_ap=1" option is set, it adds the Multi-AP backhaul subelement to the
Association Request frame and the M1 message. It then configures the new network
profile with 'multi_ap_backhaul_sta=1'. Note that this means that if the AP does
not follow the Multi-AP specification, wpa_supplicant will fail to associate.
In summary, this is the end-to-end behavior for WPS of a backhaul link (i.e.,
multi_ap=1 option is given in the wps_pbc call on the STA side, and multi_ap=2
and multi_ap_backhaul_ssid and either multi_ap_backhaul_wpa_psk or
multi_ap_backhaul_wpa_passphrase are set to the credentials of a backhaul BSS
in hostapd on Registrar AP).
1. Fronthaul BSS Beacon frames advertise WPS support (nothing Multi-AP
specific).
2. Enrollee sends Authentication frame (nothing Multi-AP specific).
3. AP sends Authentication frame (nothing Multi-AP specific).
4. Enrollee sends Association Request frame with Multi-AP IE.
5. AP sends Association Response frame with Multi-AP IE.
6. Enrollee sends M1 with additional Multi-AP subelement.
7. AP sends M8 with backhaul instead of fronthaul credentials.
8. Enrollee sends Deauthentication frame.
References
----------
[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh
[2] https://github.com/prplfoundation/prplMesh
[3] https://www.wi-fi.org/file/multi-ap-specification-v10
(requires registration)
-352
View File
@@ -1,352 +0,0 @@
hostapd and Wi-Fi Protected Setup (WPS)
=======================================
This document describes how the WPS implementation in hostapd can be
configured and how an external component on an AP (e.g., web UI) is
used to enable enrollment of client devices.
Introduction to WPS
-------------------
Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
wireless network. It allows automated generation of random keys (WPA
passphrase/PSK) and configuration of an access point and client
devices. WPS includes number of methods for setting up connections
with PIN method and push-button configuration (PBC) being the most
commonly deployed options.
While WPS can enable more home networks to use encryption in the
wireless network, it should be noted that the use of the PIN and
especially PBC mechanisms for authenticating the initial key setup is
not very secure. As such, use of WPS may not be suitable for
environments that require secure network access without chance for
allowing outsiders to gain access during the setup phase.
WPS uses following terms to describe the entities participating in the
network setup:
- access point: the WLAN access point
- Registrar: a device that control a network and can authorize
addition of new devices); this may be either in the AP ("internal
Registrar") or in an external device, e.g., a laptop, ("external
Registrar")
- Enrollee: a device that is being authorized to use the network
It should also be noted that the AP and a client device may change
roles (i.e., AP acts as an Enrollee and client device as a Registrar)
when WPS is used to configure the access point.
More information about WPS is available from Wi-Fi Alliance:
http://www.wi-fi.org/wifi-protected-setup
hostapd implementation
----------------------
hostapd includes an optional WPS component that can be used as an
internal WPS Registrar to manage addition of new WPS enabled clients
to the network. In addition, WPS Enrollee functionality in hostapd can
be used to allow external WPS Registrars to configure the access
point, e.g., for initial network setup. In addition, hostapd can proxy a
WPS registration between a wireless Enrollee and an external Registrar
(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
hostapd configuration
---------------------
WPS is an optional component that needs to be enabled in hostapd build
configuration (.config). Here is an example configuration that
includes WPS support and uses nl80211 driver interface:
CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
CONFIG_WPS_UPNP=y
Following parameter can be used to enable support for NFC config method:
CONFIG_WPS_NFC=y
Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
# Configure the driver and network interface
driver=nl80211
interface=wlan0
# WPA2-Personal configuration for the AP
ssid=wps-test
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
# Default WPA passphrase for legacy (non-WPS) clients
wpa_passphrase=12345678
# Enable random per-device PSK generation for WPS clients
# Please note that the file has to exists for hostapd to start (i.e., create an
# empty file as a starting point).
wpa_psk_file=/etc/hostapd.psk
# Enable control interface for PBC/PIN entry
ctrl_interface=/var/run/hostapd
# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
eap_server=1
# WPS configuration (AP configured, do not allow external WPS Registrars)
wps_state=2
ap_setup_locked=1
# If UUID is not configured, it will be generated based on local MAC address.
uuid=87654321-9abc-def0-1234-56789abc0000
wps_pin_requests=/var/run/hostapd.pin-req
device_name=Wireless AP
manufacturer=Company
model_name=WAP
model_number=123
serial_number=12345
device_type=6-0050F204-1
os_version=01020300
config_methods=label display push_button keypad
# if external Registrars are allowed, UPnP support could be added:
#upnp_iface=br0
#friendly_name=WPS Access Point
External operations
-------------------
WPS requires either a device PIN code (usually, 8-digit number) or a
pushbutton event (for PBC) to allow a new WPS Enrollee to join the
network. hostapd uses the control interface as an input channel for
these events.
The PIN value used in the commands must be processed by an UI to
remove non-digit characters and potentially, to verify the checksum
digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
the checksum digit is incorrect, or the processed PIN (non-digit
characters removed) if the PIN is valid.
When a client device (WPS Enrollee) connects to hostapd (WPS
Registrar) in order to start PIN mode negotiation for WPS, an
identifier (Enrollee UUID) is sent. hostapd will need to be configured
with a device password (PIN) for this Enrollee. This is an operation
that requires user interaction (assuming there are no pre-configured
PINs on the AP for a set of Enrollee).
The PIN request with information about the device is appended to the
wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
addition, hostapd control interface event is sent as a notification of
a new device. The AP could use, e.g., a web UI for showing active
Enrollees to the user and request a PIN for an Enrollee.
The PIN request file has one line for every Enrollee that connected to
the AP, but for which there was no PIN. Following information is
provided for each Enrollee (separated with tabulators):
- timestamp (seconds from 1970-01-01)
- Enrollee UUID
- MAC address
- Device name
- Manufacturer
- Model Name
- Model Number
- Serial Number
- Device category
Example line in the /var/run/hostapd.pin-req file:
1200188391 53b63a98-d29e-4457-a2ed-094d7e6a669c Intel(R) Centrino(R) Intel Corporation Intel(R) Centrino(R) - - 1-0050F204-1
Control interface data:
WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
For example:
<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
When the user enters a PIN for a pending Enrollee, e.g., on the web
UI), hostapd needs to be notified of the new PIN over the control
interface. This can be done either by using the UNIX domain socket
-based control interface directly (src/common/wpa_ctrl.c provides
helper functions for using the interface) or by calling hostapd_cli.
Example command to add a PIN (12345670) for an Enrollee:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
If the UUID-E is not available (e.g., Enrollee waits for the Registrar
to be selected before connecting), wildcard UUID may be used to allow
the PIN to be used once with any UUID:
hostapd_cli wps_pin any 12345670
To reduce likelihood of PIN being used with other devices or of
forgetting an active PIN available for potential attackers, expiration
time in seconds can be set for the new PIN (value 0 indicates no
expiration):
hostapd_cli wps_pin any 12345670 300
If the MAC address of the enrollee is known, it should be configured
to allow the AP to advertise list of authorized enrollees:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
12345670 300 00:11:22:33:44:55
After this, the Enrollee can connect to the AP again and complete WPS
negotiation. At that point, a new, random WPA PSK is generated for the
client device and the client can then use that key to connect to the
AP to access the network.
If the AP includes a pushbutton, WPS PBC mode can be used. It is
enabled by pushing a button on both the AP and the client at about the
same time (2 minute window). hostapd needs to be notified about the AP
button pushed event over the control interface, e.g., by calling
hostapd_cli:
hostapd_cli wps_pbc
At this point, the client has two minutes to complete WPS negotiation
which will generate a new WPA PSK in the same way as the PIN method
described above.
When an external Registrar is used, the AP can act as an Enrollee and
use its AP PIN. A static AP PIN (e.g., one one a label in the AP
device) can be configured in hostapd.conf (ap_pin parameter). A more
secure option is to use hostapd_cli wps_ap_pin command to enable the
AP PIN only based on user action (and even better security by using a
random AP PIN for each session, i.e., by using "wps_ap_pin random"
command with a timeout value). Following commands are available for
managing the dynamic AP PIN operations:
hostapd_cli wps_ap_pin disable
- disable AP PIN (i.e., do not allow external Registrars to use it to
learn the current AP settings or to reconfigure the AP)
hostapd_cli wps_ap_pin random [timeout]
- generate a random AP PIN and enable it
- if the optional timeout parameter is given, the AP PIN will be enabled
for the specified number of seconds
hostapd_cli wps_ap_pin get
- fetch the current AP PIN
hostapd_cli wps_ap_pin set <PIN> [timeout]
- set the AP PIN and enable it
- if the optional timeout parameter is given, the AP PIN will be enabled
for the specified number of seconds
hostapd_cli get_config
- display the current configuration
hostapd_cli wps_config <new SSID> <auth> <encr> <new key>
examples:
hostapd_cli wps_config testing WPA2PSK CCMP 12345678
hostapd_cli wps_config "no security" OPEN NONE ""
<auth> must be one of the following: OPEN WPAPSK WPA2PSK
<encr> must be one of the following: NONE WEP TKIP CCMP
Credential generation and configuration changes
-----------------------------------------------
By default, hostapd generates credentials for Enrollees and processing
AP configuration updates internally. However, it is possible to
control these operations from external programs, if desired.
The internal credential generation can be disabled with
skip_cred_build=1 option in the configuration. extra_cred option will
then need to be used to provide pre-configured Credential attribute(s)
for hostapd to use. The exact data from this binary file will be sent,
i.e., it will have to include valid WPS attributes. extra_cred can
also be used to add additional networks if the Registrar is used to
configure credentials for multiple networks.
Processing of received configuration updates can be disabled with
wps_cred_processing=1 option. When this is used, an external program
is responsible for creating hostapd configuration files and processing
configuration updates based on messages received from hostapd over
control interface. This will also include the initial configuration on
first successful registration if the AP is initially set in
unconfigured state.
Following control interface messages are sent out for external programs:
WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
For example:
<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
This can be used to trigger change from unconfigured to configured
state (random configuration based on the first successful WPS
registration). In addition, this can be used to update AP UI about the
status of WPS registration progress.
WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
For example:
<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
This can be used to update the externally stored AP configuration and
then update hostapd configuration (followed by restarting of hostapd).
WPS with NFC
------------
WPS can be used with NFC-based configuration method. An NFC tag
containing a password token from the Enrollee can be used to
authenticate the connection instead of the PIN. In addition, an NFC tag
with a configuration token can be used to transfer AP settings without
going through the WPS protocol.
When the AP acts as an Enrollee, a local NFC tag with a password token
can be used by touching the NFC interface of an external Registrar. The
wps_nfc_token command is used to manage use of the NFC password token
from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
password token (in place of AP PIN) and "wps_nfc_token disable" disables
the NFC password token.
The NFC password token that is either pre-configured in the
configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
wpa_supplicant can be used to generate NFC password tokens during
manufacturing (each AP needs to have its own random keys).
The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
NFC configuration token. The output value from this command is a hexdump
of the current AP configuration (WPS parameter requests this to include
only the WPS attributes; NDEF parameter requests additional NDEF
encapsulation to be included). This data needs to be written to an NFC
tag with an external program. Once written, the NFC configuration token
can be used to touch an NFC interface on a station to provision the
credentials needed to access the network.
When the NFC device on the AP reads an NFC tag with a MIME media type
"application/vnd.wfa.wsc", the NDEF message payload (with or without
NDEF encapsulation) can be delivered to hostapd using the
following hostapd_cli command:
wps_nfc_tag_read <hexdump of payload>
If the NFC tag contains a password token, the token is added to the
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.
"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
contents of a Handover Select Message for connection handover when this
does not depend on the contents of the Handover Request Message. The
first argument selects the format of the output data and the second
argument selects which type of connection handover is requested (WPS =
Wi-Fi handover as specified in WSC 2.0).
"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
<carrier from handover select>" is used to report completed NFC
connection handover. The first parameter indicates whether the local
device initiated or responded to the connection handover and the carrier
records are the selected carrier from the handover request and select
messages as a hexdump.
-214
View File
@@ -1,214 +0,0 @@
# Example hostapd build time configuration
#
# This file lists the configuration options that are used when building the
# hostapd binary. All lines starting with # are ignored. Configuration option
# lines must be commented out complete, if they are not to be included, i.e.,
# just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cass, these lines should use += in order not
# to override previous values of the variables.
# Driver interface for Host AP driver
#CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
# Driver interface for drivers using the nl80211 kernel interface
#CONFIG_DRIVER_NL80211=y
# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
# shipped with your distribution yet. If that is the case, you need to build
# newer libnl version and point the hostapd build to use it.
#LIBNL=/usr/src/libnl
#CFLAGS += -I$(LIBNL)/include
#LIBS += -L$(LIBNL)/lib
CONFIG_LIBNL20=y
# QCA vendor extensions to nl80211
CONFIG_DRIVER_NL80211_QCA=y
# Broadcom vendor extensions to nl80211
#CONFIG_DRIVER_NL80211_BRCM=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
#LIBS += -L/usr/local/lib
#LIBS_p += -L/usr/local/lib
#LIBS_c += -L/usr/local/lib
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
# WPA2/IEEE 802.11i RSN pre-authentication
#CONFIG_RSN_PREAUTH=y
# Support Operating Channel Validation
#CONFIG_OCV=y
# Integrated EAP server
#CONFIG_EAP=y
# EAP-MD5 for the integrated EAP server
#CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP server
#CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP server
#CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP server
#CONFIG_EAP_PEAP=y
# EAP-GTC for the integrated EAP server
#CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP server
#CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-AKA' for the integrated EAP server
# This requires CONFIG_EAP_AKA to be enabled, too.
#CONFIG_EAP_AKA_PRIME=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
#CONFIG_EAP_FAST=y
# Wi-Fi Protected Setup (WPS)
CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE Std 802.11r-2008 (Fast BSS Transition)
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
#CONFIG_NO_STDOUT_DEBUG=y
# Add support for writing debug log to Android logcat instead of standard output
CONFIG_ANDROID_LOG=y
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
# Remove support for RADIUS
CONFIG_NO_RADIUS=y
# Remove support for VLANs
#CONFIG_NO_VLAN=y
# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
# Select wrapper for operatins system and C library specific functions
# unix = UNIX/POSIX like systems (default)
# win32 = Windows systems
# none = Empty template
CONFIG_OS=unix
# Enable tracing code for developer debugging
# This tracks use of memory allocations and other registrations and reports
# incorrect use with a backtrace of call (or allocation) location.
#CONFIG_WPA_TRACE=y
# For BSD, comment out these.
#LIBS += -lexecinfo
#LIBS_p += -lexecinfo
#LIBS_c += -lexecinfo
# Use libbfd to get more details for developer debugging
# This enables use of libbfd to get more detailed symbols for the backtraces
# generated by CONFIG_WPA_TRACE=y.
#CONFIG_WPA_TRACE_BFD=y
# For BSD, comment out these.
#LIBS += -lbfd -liberty -lz
#LIBS_p += -lbfd -liberty -lz
#LIBS_c += -lbfd -liberty -lz
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
# Enable AP
CONFIG_AP=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
# Multiband Operation support
# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
# Include internal line edit mode in hostapd_cli.
CONFIG_WPA_CLI_EDIT=y
# Opportunistic Wireless Encryption (OWE)
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
# Wpa_supplicant's random pool is not necessary on Android. Randomness is
# already provided by the entropymixer service which ensures sufficient
# entropy is maintained across reboots. Commit b410eb1913 'Initialize
# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
# Wired equivalent privacy (WEP)
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used for anything anymore. The
# functionality needed to use WEP is available in the current hostapd
# release under this optional build parameter. This functionality is subject to
# be completely removed in a future release.
CONFIG_WEP=y
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
/*
* hostapd / Configuration file parser
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
struct hostapd_config * hostapd_config_read(const char *fname);
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, 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 */
-5284
View File
File diff suppressed because it is too large Load Diff
-39
View File
@@ -1,39 +0,0 @@
/*
* hostapd / UNIX domain socket -based control interface
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef CTRL_IFACE_H
#define CTRL_IFACE_H
#ifndef CONFIG_NO_CTRL_IFACE
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
}
static inline int
hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
{
return 0;
}
static inline void
hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
{
}
#endif /* CONFIG_NO_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
-412
View File
@@ -1,412 +0,0 @@
# Example hostapd build time configuration
#
# This file lists the configuration options that are used when building the
# hostapd binary. All lines starting with # are ignored. Configuration option
# lines must be commented out complete, if they are not to be included, i.e.,
# just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cass, these lines should use += in order not
# to override previous values of the variables.
# Driver interface for Host AP driver
CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
# QCA vendor extensions to nl80211
#CONFIG_DRIVER_NL80211_QCA=y
# driver_nl80211.c requires libnl. If you are compiling it yourself
# you may need to point hostapd to your version of libnl.
#
#CFLAGS += -I$<path to libnl include files>
#LIBS += -L$<path to libnl library files>
# Use libnl v2.0 (or 3.0) libraries.
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
#LIBS += -L/usr/local/lib
#LIBS_p += -L/usr/local/lib
#LIBS_c += -L/usr/local/lib
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# Support Operating Channel Validation
#CONFIG_OCV=y
# Integrated EAP server
CONFIG_EAP=y
# EAP Re-authentication Protocol (ERP) in integrated EAP server
CONFIG_ERP=y
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP server
CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP server
CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP server
CONFIG_EAP_PEAP=y
# EAP-GTC for the integrated EAP server
CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP server
CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-AKA' for the integrated EAP server
# This requires CONFIG_EAP_AKA to be enabled, too.
#CONFIG_EAP_AKA_PRIME=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-pwd for the integrated EAP server (secure authentication with a password)
#CONFIG_EAP_PWD=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
#CONFIG_EAP_FAST=y
# EAP-TEAP for the integrated EAP server
# Note: The current EAP-TEAP implementation is experimental and should not be
# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number
# of conflicting statements and missing details and the implementation has
# vendor specific workarounds for those and as such, may not interoperate with
# any other implementation. This should not be used for anything else than
# experimentation and interoperability testing until those issues has been
# resolved.
#CONFIG_EAP_TEAP=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# Enable WPS support with NFC config method
#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
# EAP-EKE for the integrated EAP server
#CONFIG_EAP_EKE=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE Std 802.11r-2008 (Fast BSS Transition)
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
# IEEE 802.11ac (Very High Throughput) support
#CONFIG_IEEE80211AC=y
# 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.
#CONFIG_NO_STDOUT_DEBUG=y
# Add support for writing debug log to a file: -f /tmp/hostapd.log
# Disabled by default.
#CONFIG_DEBUG_FILE=y
# 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
# same file, e.g., using trace-cmd.
#CONFIG_DEBUG_LINUX_TRACING=y
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
# Remove support for RADIUS
#CONFIG_NO_RADIUS=y
# Remove support for VLANs
#CONFIG_NO_VLAN=y
# Enable support for fully dynamic VLANs. This enables hostapd to
# automatically create bridge and VLAN interfaces if necessary.
#CONFIG_FULL_DYNAMIC_VLAN=y
# Use netlink-based kernel API for VLAN operations instead of ioctl()
# Note: This requires libnl 3.1 or newer.
#CONFIG_VLAN_NETLINK=y
# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
# Enable tracing code for developer debugging
# This tracks use of memory allocations and other registrations and reports
# incorrect use with a backtrace of call (or allocation) location.
#CONFIG_WPA_TRACE=y
# For BSD, comment out these.
#LIBS += -lexecinfo
#LIBS_p += -lexecinfo
#LIBS_c += -lexecinfo
# Use libbfd to get more details for developer debugging
# This enables use of libbfd to get more detailed symbols for the backtraces
# generated by CONFIG_WPA_TRACE=y.
#CONFIG_WPA_TRACE_BFD=y
# For BSD, comment out these.
#LIBS += -lbfd -liberty -lz
#LIBS_p += -lbfd -liberty -lz
#LIBS_c += -lbfd -liberty -lz
# hostapd depends on strong random number generation being available from the
# operating system. os_get_random() function is used to fetch random data when
# needed, e.g., for key generation. On Linux and BSD systems, this works by
# reading /dev/urandom. It should be noted that the OS entropy pool needs to be
# properly initialized before hostapd is started. This is important especially
# on embedded devices that do not have a hardware random number generator and
# may by default start up with minimal entropy available for random number
# generation.
#
# As a safety net, hostapd is by default trying to internally collect
# additional entropy for generating random data to mix in with the data
# fetched from the OS. This by itself is not considered to be very strong, but
# it may help in cases where the system pool is not initialized properly.
# However, it is very strongly recommended that the system pool is initialized
# with enough entropy either by using hardware assisted random number
# generator or by storing state over device reboots.
#
# hostapd can be configured to maintain its own entropy store over restarts to
# enhance random number generation. This is not perfect, but it is much more
# secure than using the same sequence of random numbers after every reboot.
# This can be enabled with -e<entropy file> command line option. The specified
# file needs to be readable and writable by hostapd.
#
# If the os_get_random() is known to provide strong random data (e.g., on
# Linux/BSD, the board in question is known to have reliable source of random
# data from /dev/urandom), the internal hostapd random pool can be disabled.
# This will save some in binary size and CPU use. However, this should only be
# considered for builds that are known to be used on devices that meet the
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
# Should we attempt to use the getrandom(2) call that provides more reliable
# yet secure randomness source than /dev/random on Linux 3.17 and newer.
# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
#CONFIG_GETRANDOM=y
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
# Should we use kqueue instead of select? Select is used by default.
#CONFIG_ELOOP_KQUEUE=y
# Select TLS implementation
# 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
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
# can be enabled to get a stronger construction of messages when block ciphers
# are used.
#CONFIG_TLSV11=y
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
# can be enabled to enable use of stronger crypto algorithms.
#CONFIG_TLSV12=y
# 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
# and drawbacks of this option.
#CONFIG_INTERNAL_LIBTOMMATH=y
#ifndef CONFIG_INTERNAL_LIBTOMMATH
#LTM_PATH=/usr/src/libtommath-0.39
#CFLAGS += -I$(LTM_PATH)
#LIBS += -L$(LTM_PATH)
#LIBS_p += -L$(LTM_PATH)
#endif
# At the cost of about 4 kB of additional binary size, the internal LibTomMath
# can be configured to include faster routines for exptmod, sqr, and div to
# speed up DH and RSA calculation considerably
#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks.
#CONFIG_INTERWORKING=y
# Hotspot 2.0
#CONFIG_HS20=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
# Enable CLI commands for FST testing
#CONFIG_FST_TEST=y
# Testing options
# This can be used to enable some testing options (see also the example
# configuration file) that are really useful only for testing clients that
# connect to this hostapd. These options allow, for example, to drop a
# certain percentage of probe requests or auth/(re)assoc frames.
#
#CONFIG_TESTING_OPTIONS=y
# Automatic Channel Selection
# This will allow hostapd to pick the channel automatically when channel is set
# to "acs_survey" or "0". Eventually, other ACS algorithms can be added in
# similar way.
#
# Automatic selection is currently only done through initialization, later on
# we hope to do background checks to keep us moving to more ideal channels as
# time goes by. ACS is currently only supported through the nl80211 driver and
# your driver must have survey dump capability that is filled by the driver
# during scanning.
#
# You can customize the ACS survey algorithm with the hostapd.conf variable
# acs_num_scans.
#
# Supported ACS drivers:
# * ath9k
# * ath5k
# * ath10k
#
# For more details refer to:
# https://wireless.wiki.kernel.org/en/users/documentation/acs
#
#CONFIG_ACS=y
# Multiband Operation support
# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
# Client Taxonomy
# Has the AP retain the Probe Request and (Re)Association Request frames from
# 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)
#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
# Airtime policy support
#CONFIG_AIRTIME_POLICY=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
# Wired equivalent privacy (WEP)
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used for anything anymore. The
# functionality needed to use WEP is available in the current hostapd
# release under this optional build parameter. This functionality is subject to
# be completely removed in a future release.
#CONFIG_WEP=y
# Remove all TKIP functionality
# TKIP is an old cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used anymore. For now, the default hostapd
# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
# that functionality is subject to be removed in the future.
#CONFIG_NO_TKIP=y
# Pre-Association Security Negotiation (PASN)
# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
# design is still subject to change. As such, this should not yet be enabled in
# production use.
# This requires CONFIG_IEEE80211W=y to be enabled, too.
#CONFIG_PASN=y
# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect)
CONFIG_DPP=y
# DPP version 2 support
CONFIG_DPP2=y
# DPP version 3 support (experimental and still changing; do not enable for
# production use)
#CONFIG_DPP3=y
-155
View File
@@ -1,155 +0,0 @@
/*
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "eap_server/eap_methods.h"
#include "eap_register.h"
/**
* eap_server_register_methods - Register statically linked EAP server methods
* Returns: 0 on success, -1 or -2 on failure
*
* This function is called at program initialization to register all EAP
* methods that were linked in statically.
*/
int eap_server_register_methods(void)
{
int ret = 0;
#ifdef EAP_SERVER_IDENTITY
if (ret == 0)
ret = eap_server_identity_register();
#endif /* EAP_SERVER_IDENTITY */
#ifdef EAP_SERVER_MD5
if (ret == 0)
ret = eap_server_md5_register();
#endif /* EAP_SERVER_MD5 */
#ifdef EAP_SERVER_TLS
if (ret == 0)
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_UNAUTH_TLS
if (ret == 0)
ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_TLS
#ifdef CONFIG_HS20
if (ret == 0)
ret = eap_server_wfa_unauth_tls_register();
#endif /* CONFIG_HS20 */
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
#endif /* EAP_SERVER_MSCHAPV2 */
#ifdef EAP_SERVER_PEAP
if (ret == 0)
ret = eap_server_peap_register();
#endif /* EAP_SERVER_PEAP */
#ifdef EAP_SERVER_TLV
if (ret == 0)
ret = eap_server_tlv_register();
#endif /* EAP_SERVER_TLV */
#ifdef EAP_SERVER_GTC
if (ret == 0)
ret = eap_server_gtc_register();
#endif /* EAP_SERVER_GTC */
#ifdef EAP_SERVER_TTLS
if (ret == 0)
ret = eap_server_ttls_register();
#endif /* EAP_SERVER_TTLS */
#ifdef EAP_SERVER_SIM
if (ret == 0)
ret = eap_server_sim_register();
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_AKA
if (ret == 0)
ret = eap_server_aka_register();
#endif /* EAP_SERVER_AKA */
#ifdef EAP_SERVER_AKA_PRIME
if (ret == 0)
ret = eap_server_aka_prime_register();
#endif /* EAP_SERVER_AKA_PRIME */
#ifdef EAP_SERVER_PAX
if (ret == 0)
ret = eap_server_pax_register();
#endif /* EAP_SERVER_PAX */
#ifdef EAP_SERVER_PSK
if (ret == 0)
ret = eap_server_psk_register();
#endif /* EAP_SERVER_PSK */
#ifdef EAP_SERVER_SAKE
if (ret == 0)
ret = eap_server_sake_register();
#endif /* EAP_SERVER_SAKE */
#ifdef EAP_SERVER_GPSK
if (ret == 0)
ret = eap_server_gpsk_register();
#endif /* EAP_SERVER_GPSK */
#ifdef EAP_SERVER_VENDOR_TEST
if (ret == 0)
ret = eap_server_vendor_test_register();
#endif /* EAP_SERVER_VENDOR_TEST */
#ifdef EAP_SERVER_FAST
if (ret == 0)
ret = eap_server_fast_register();
#endif /* EAP_SERVER_FAST */
#ifdef EAP_SERVER_TEAP
if (ret == 0)
ret = eap_server_teap_register();
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_WSC
if (ret == 0)
ret = eap_server_wsc_register();
#endif /* EAP_SERVER_WSC */
#ifdef EAP_SERVER_IKEV2
if (ret == 0)
ret = eap_server_ikev2_register();
#endif /* EAP_SERVER_IKEV2 */
#ifdef EAP_SERVER_TNC
if (ret == 0)
ret = eap_server_tnc_register();
#endif /* EAP_SERVER_TNC */
#ifdef EAP_SERVER_PWD
if (ret == 0)
ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */
#ifdef EAP_SERVER_EKE
if (ret == 0)
ret = eap_server_eke_register();
#endif /* EAP_SERVER_EKE */
return ret;
}
-14
View File
@@ -1,14 +0,0 @@
/*
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef EAP_REGISTER_H
#define EAP_REGISTER_H
int eap_server_register_methods(void);
#endif /* EAP_REGISTER_H */
-77
View File
@@ -1,77 +0,0 @@
Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
Test matrix
+) tested successfully
F) failed
-) peer did not support
?) not tested
XSupplicant --------------------------------.
Intel PROSet ---------------------------. |
Windows XP -------------------------. | |
Mac OS X 10.4 ------------------. | | |
Nokia S60 ------------------. | | | |
wpa_supplicant ---------. | | | | |
| | | | | |
EAP-MD5 + - ? ? -
EAP-GTC + - ? - -
EAP-MSCHAPv2 + - ? - -
EAP-TLS + + +1 + +
EAP-PEAPv0/MSCHAPv2 + + + + + +
EAP-PEAPv0/GTC + + + - +
EAP-PEAPv0/MD5 + - + - -
EAP-PEAPv0/TLS + F - + +
EAP-PEAPv0/SIM + + - - -
EAP-PEAPv0/AKA + + - - -
EAP-PEAPv0/PSK + - - - -
EAP-PEAPv0/PAX + - - - -
EAP-PEAPv0/SAKE + - - - -
EAP-PEAPv0/GPSK + - - - -
EAP-PEAPv1/MSCHAPv2 + + + - + +
EAP-PEAPv1/GTC + + + - +
EAP-PEAPv1/MD5 + - + - -
EAP-PEAPv1/TLS + F - - +
EAP-PEAPv1/SIM + + - - -
EAP-PEAPv1/AKA + + - - -
EAP-PEAPv1/PSK + - - - -
EAP-PEAPv1/PAX + - - - -
EAP-PEAPv1/SAKE + - - - -
EAP-PEAPv1/GPSK + - - - -
EAP-TTLS/CHAP + - + - + +
EAP-TTLS/MSCHAP + - + - + +
EAP-TTLS/MSCHAPv2 + + + - + +
EAP-TTLS/PAP + - + - + +
EAP-TTLS/EAP-MD5 + - - - - +
EAP-TTLS/EAP-GTC + + - - -
EAP-TTLS/EAP-MSCHAPv2 + + - - -
EAP-TTLS/EAP-TLS + F - - -
EAP-TTLS/EAP-SIM + + - - -
EAP-TTLS/EAP-AKA + + - - -
EAP-TTLS + TNC + - - - -
EAP-SIM + + - - +
EAP-AKA + + - - -
EAP-PAX + - - - -
EAP-SAKE + - - - -
EAP-GPSK + - - - -
EAP-FAST/MSCHAPv2(prov) + - F - F
EAP-FAST/GTC(auth) + - + - +
EAP-FAST/MSCHAPv2(aprov)+ - F - F
EAP-FAST/GTC(aprov) + - F - F
EAP-FAST/MD5(aprov) + - - - -
EAP-FAST/TLS(aprov) + - - - -
EAP-FAST/SIM(aprov) + - - - -
EAP-FAST/AKA(aprov) + - - - -
EAP-FAST/MSCHAPv2(auth) + - + - +
EAP-FAST/MD5(auth) + - + - -
EAP-FAST/TLS(auth) + - - - -
EAP-FAST/SIM(auth) + - - - -
EAP-FAST/AKA(auth) + - - - -
EAP-FAST + TNC + - - - -
EAP-IKEv2 + - - - -
EAP-TNC + - - - -
1) EAP-TLS itself worked, but peer certificate validation failed at
least when using the internal TLS server (peer included incorrect
certificates in the chain?)
-18
View File
@@ -1,18 +0,0 @@
/*
* hostapd module tests
* Copyright (c) 2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/module_tests.h"
int hapd_module_tests(void)
{
wpa_printf(MSG_INFO, "hostapd module tests");
return 0;
}
-1109
View File
File diff suppressed because it is too large Load Diff
-15
View File
@@ -1,15 +0,0 @@
# Parameters for Milenage (Example algorithms for AKA).
# The example Ki, OPc, and AMF values here are from 3GPP TS 35.208 v6.0.0
# 4.3.20 Test Set 20. SQN is the last used SQN value.
# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM)
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
# stub values will need to be included in this file.
# IMSI Ki OPc AMF SQN [RES_len]
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
# Example using truncated 32-bit RES instead of 64-bit default
232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
# These values are from Test Set 19 which has the AMF separation bit set to 1
# and as such, is suitable for EAP-AKA' test.
555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1
-104
View File
@@ -1,104 +0,0 @@
HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
database/authentication gateway interface to HLR/AuC. It could be
replaced with an implementation of SS7 gateway to GSM/UMTS
authentication center (HLR/AuC). hostapd will send SIM/AKA
authentication queries over a UNIX domain socket to and external
program, e.g., hlr_auc_gw.
hlr_auc_gw can be configured with GSM and UMTS authentication data with
text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
GSM triplet data is used for a more static configuration (e.g., triplets
extracted from a SIM card).
Alternatively, hlr_auc_gw can be built with support for an SQLite
database for more dynamic operations. This is enabled by adding
"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
clean; make hlr_auc_gw" in this directory).
hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
is configured with command line parameters:
hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
[-D<DB file>] [-i<IND len in bits>]
options:
-h = show this usage help
-u = update SQN in Milenage file on exit
-s<socket path> = path for UNIX domain socket
(default: /tmp/hlr_auc_gw.sock)
-g<triplet file> = path for GSM authentication triplets
-m<milenage file> = path for Milenage keys
-D<DB file> = path to SQLite database
-i<IND len in bits> = IND length for SQN (default: 5)
The SQLite database can be initialized with sqlite, e.g., by running
following commands in "sqlite3 /path/to/hlr_auc_gw.db":
CREATE TABLE milenage(
imsi INTEGER PRIMARY KEY NOT NULL,
ki CHAR(32) NOT NULL,
opc CHAR(32) NOT NULL,
amf CHAR(4) NOT NULL,
sqn CHAR(12) NOT NULL
);
INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
232010000000000,
'90dca4eda45b53cf0f12d7c9c3bc6a89',
'cb9cccc4b9258e6dca4760379fb82581',
'61df',
'000000000000'
);
INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
555444333222111,
'5122250214c33e723a5dd523fc145fc0',
'981d464c7c52eb6e5036234984ad0bcf',
'c3ab',
'16f3b3f70fc1'
);
hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
pseudonyms and reauth information into a SQLite database. This is
configured with the db parameter within the eap_sim_db configuration
option.
"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
Milenage parameters based on IMSI from the database. The database can be
updated dynamically while hlr_auc_gw is running to add/remove/modify
entries.
Example configuration files for hostapd to operate as a RADIUS
authentication server for EAP-SIM/AKA/AKA':
hostapd.conf:
driver=none
radius_server_clients=hostapd.radius_clients
eap_server=1
eap_user_file=hostapd.eap_user
eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
eap_sim_aka_result_ind=1
hostapd.radius_clients:
0.0.0.0/0 radius
hostapd.eap_user:
"0"* AKA
"1"* SIM
"2"* AKA
"3"* SIM
"4"* AKA
"5"* SIM
"6"* AKA'
"7"* AKA'
"8"* AKA'
-59
View File
@@ -1,59 +0,0 @@
.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd
.SH NAME
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
.SH SYNOPSIS
.B hostapd
[\-hdBKtv] [\-P <PID file>] <configuration file(s)>
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd
daemon.
.PP
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211).
.B hostapd
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
.B hostapd
supports separate frontend programs and an example text-based frontend,
.BR hostapd_cli ,
is included with
.BR hostapd .
.SH OPTIONS
A summary of options is included below.
For a complete description, run
.BR hostapd
from the command line.
.TP
.B \-h
Show usage.
.TP
.B \-d
Show more debug messages.
.TP
.B \-dd
Show even more debug messages.
.TP
.B \-B
Run daemon in the background.
.TP
.B \-P <PID file>
Path to PID file.
.TP
.B \-K
Include key data in debug messages.
.TP
.B \-t
Include timestamps in some debug messages.
.TP
.B \-v
Show hostapd version.
.SH SEE ALSO
.BR hostapd_cli (1).
.SH AUTHOR
hostapd was written by Jouni Malinen <j@w1.fi>.
.PP
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
for the Debian project (but may be used by others).
-6
View File
@@ -1,6 +0,0 @@
# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
# with the AP. Optional VLAN ID can be assigned for clients based on the
# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used.
00:11:22:33:44:55
00:66:77:88:99:aa
00:00:22:33:44:55 1
-19
View File
@@ -1,19 +0,0 @@
#
# init.rc fragment for hostapd on Android
# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
#
on post-fs-data
mkdir /data/misc/wifi/hostapd 0770 wifi wifi
service hostapd /vendor/bin/hostapd \
/data/misc/wifi/hostapd.conf
class main
user wifi
writepid /data/misc/wifi/hostapd.pid
group wifi
disabled
oneshot
-3047
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
# with the AP.
00:20:30:40:50:60
00:ab:cd:ef:12:34
00:00:30:40:50:60
-103
View File
@@ -1,103 +0,0 @@
# hostapd user database for integrated EAP server
# Each line must contain an identity, EAP method(s), and an optional password
# separated with whitespace (space or tab). The identity and password must be
# double quoted ("user"). Password can alternatively be stored as
# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
# that the plaintext password does not need to be included in the user file.
# Password hash is stored as hash:<16-octets of hex data> without quotation
# marks.
# [2] flag in the end of the line can be used to mark users for tunneled phase
# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
# identity can be used in the unencrypted phase 1 and the real user identity
# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
# access is needed, two user entries is needed, one for phase 1 and another
# with the same username for phase 2.
#
# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
# password option.
# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
# password.
# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
#
# * can be used as a wildcard to match any user identity. The main purposes for
# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
# avoid having to configure every certificate for EAP-TLS authentication. The
# first matching entry is selected, so * should be used as the last phase 1
# user entry.
#
# "prefix"* can be used to match the given prefix and anything after this. The
# main purpose for this is to be able to avoid EAP method negotiation when the
# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
# is only allowed for phase 1 identities.
#
# Multiple methods can be configured to make the authenticator try them one by
# one until the peer accepts one. The method names are separated with a
# comma (,).
#
# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
# version based on the Phase 1 identity. Without this flag, the EAP
# authenticator advertises the highest supported version and select the version
# based on the first PEAP packet from the supplicant.
#
# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
# Tunneled EAP methods are configured with standard EAP method name and [2]
# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
# hash.
#
# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly
# to the way radius_auth_req_attr is used for Access-Request packet in
# hostapd.conf. For EAP server, this is configured separately for each user
# entry with radius_accept_attr=<value> line(s) following the main user entry
# line.
# Phase 1 users
"user" MD5 "password"
"test user" MD5 "secret"
"example user" TLS
"DOMAIN\user" MSCHAPV2 "password"
"gtc user" GTC "password"
"pax user" PAX "unknown"
"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef
"psk user" PSK "unknown"
"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef
"sake.user@example.com" SAKE 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
"ttls" TTLS
"not anonymous" PEAP
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
"0"* AKA,TTLS,TLS,PEAP,SIM
"1"* SIM,TTLS,TLS,PEAP,AKA
"2"* AKA,TTLS,TLS,PEAP,SIM
"3"* SIM,TTLS,TLS,PEAP,AKA
"4"* AKA,TTLS,TLS,PEAP,SIM
"5"* SIM,TTLS,TLS,PEAP,AKA
"6"* AKA'
"7"* AKA'
"8"* AKA'
# Wildcard for all other identities
* PEAP,TTLS,TLS,SIM,AKA
# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
"t-md5" MD5 "password" [2]
"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2]
"t-gtc" GTC "password" [2]
"not anonymous" MSCHAPV2 "password" [2]
"user" MD5,GTC,MSCHAPV2 "password" [2]
"test user" MSCHAPV2 hash:000102030405060708090a0b0c0d0e0f [2]
"ttls-user" TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2 "password" [2]
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
"0"* AKA [2]
"1"* SIM [2]
"2"* AKA [2]
"3"* SIM [2]
"4"* AKA [2]
"5"* SIM [2]
"6"* AKA' [2]
"7"* AKA' [2]
"8"* AKA' [2]
-42
View File
@@ -1,42 +0,0 @@
CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
remediation TEXT,
phase2 INTEGER,
t_c_timestamp INTEGER
);
CREATE TABLE wildcards(
identity TEXT PRIMARY KEY,
methods TEXT
);
INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
CREATE TABLE authlog(
timestamp TEXT,
session TEXT,
nas_ip TEXT,
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
);
-4
View File
@@ -1,4 +0,0 @@
# RADIUS client configuration for the RADIUS server
10.1.2.3 secret passphrase
192.168.1.0/24 another very secret passphrase
0.0.0.0/0 radius
-9
View File
@@ -1,9 +0,0 @@
# Example GSM authentication triplet file for EAP-SIM authenticator
# IMSI:Kc:SRES:RAND
# IMSI: ASCII string (numbers)
# Kc: hex, 8 octets
# SRES: hex, 4 octets
# RAND: hex, 16 octets
234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
-9
View File
@@ -1,9 +0,0 @@
# VLAN ID to network interface mapping
1 vlan1
2 vlan2
3 vlan3
100 guest
# Optional wildcard entry matching all VLAN IDs. The first # in the interface
# name will be replaced with the VLAN ID. The network interfaces are created
# (and removed) dynamically based on the use.
* vlan#
-21
View File
@@ -1,21 +0,0 @@
# List of WPA PSKs. Each line, except for empty lines and lines starting
# with #, must contain a MAC address and PSK separated with a space.
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
# characters or as a 256-bit hex PSK (64 hex digits).
# An optional key identifier can be added by prefixing the line with
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
# An optional WPS tag can be added by prefixing the line with
# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
# generating a PSK for a WPS Enrollee instead of generating a new random
# per-Enrollee PSK.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
wps=1 00:00:00:00:00:00 passphrase for WPS
wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs
-89
View File
@@ -1,89 +0,0 @@
.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface"
.SH NAME
hostapd_cli \- hostapd command-line interface
.SH SYNOPSIS
.B hostapd_cli
[\-p<path>] [\-i<ifname>] [\-a<path>] [\-hvB] [command..]
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd_cli
utility.
.PP
.B hostapd_cli
is a command-line interface for the
.B hostapd
daemon.
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
For more information about
.B hostapd
refer to the
.BR hostapd (8)
man page.
.SH OPTIONS
A summary of options is included below.
For a complete description, run
.BR hostapd_cli
from the command line.
.TP
.B \-p<path>
Path to find control sockets.
Default: /var/run/hostapd
.TP
.B \-i<ifname>
Interface to listen on.
Default: first interface found in socket path.
.TP
.B \-a<path>
Run in daemon mode executing the action file based on events from hostapd.
.TP
.B \-B
Run a daemon in the background.
.TP
.B \-h
Show usage.
.TP
.B \-v
Show hostapd_cli version.
.SH COMMANDS
A summary of commands is included below.
For a complete description, run
.BR hostapd_cli
from the command line.
.TP
.B mib
Get MIB variables (dot1x, dot11, radius).
.TP
.B sta <addr>
Get MIB variables for one station.
.TP
.B all_sta
Get MIB variables for all stations.
.TP
.B help
Get usage help.
.TP
.B interface [ifname]
Show interfaces/select interface.
.TP
.B level <debug level>
Change debug level.
.TP
.B license
Show full
.B hostapd_cli
license.
.TP
.B quit
Exit hostapd_cli.
.SH SEE ALSO
.BR hostapd (8).
.SH AUTHOR
hostapd_cli was written by Jouni Malinen <j@w1.fi>.
.PP
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
for the Debian project (but may be used by others).
File diff suppressed because it is too large Load Diff
-9
View File
@@ -1,9 +0,0 @@
Logwatch is a utility for analyzing system logs and provide a human
readable summary. This directory has a configuration file and a log
analyzer script for parsing hostapd system log entries for logwatch.
These files can be installed by copying them to following locations:
/etc/log.d/conf/services/hostapd.conf
/etc/log.d/scripts/services/hostapd
More information about logwatch is available from http://www.logwatch.org/
-65
View File
@@ -1,65 +0,0 @@
#!/usr/bin/perl -w
#
# Logwatch script for hostapd
#
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
# Distributed under the terms of the GNU General Public License v2
# Alternatively, this file may be distributed under the terms of the BSD License
use strict;
my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
my $debugcounter = 1;
my %hostapd;
my @unmatched;
if ($debug >= 5) {
print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
}
while (defined(my $line = <STDIN>)) {
if ($debug >= 5) {
print STDERR "DEBUG($debugcounter): $line";
$debugcounter++;
}
chomp($line);
if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
unless ($detail == 10) {
# collapse association events
$details =~ s/^(associated) .*$/$1/i;
}
$hostapd{$iface}->{$mac}->{$layer}->{$details}++;
} else {
push @unmatched, "$line\n";
}
}
if (keys %hostapd) {
foreach my $iface (sort keys %hostapd) {
print "Interface $iface:\n";
foreach my $mac (sort keys %{$hostapd{$iface}}) {
print " Client MAC Address $mac:\n";
foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
print " $layer:\n";
foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
print " $details";
my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
if ($count > 1) {
print ": " . $count . " Times";
}
print "\n";
}
}
}
}
}
if ($#unmatched >= 0) {
print "\n**Unmatched Entries**\n";
print @unmatched;
}
exit(0);
-10
View File
@@ -1,10 +0,0 @@
# Logwatch configuration for hostapd
#
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
# Distributed under the terms of the GNU General Public License v2
# Alternatively, this file may be distributed under the terms of the BSD License
Title = "hostapd"
LogFile = messages
*OnlyService = hostapd
*RemoveHeaders
-940
View File
@@ -1,940 +0,0 @@
/*
* hostapd / main()
* Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <syslog.h>
#include <grp.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
#include "common/dpp.h"
#include "drivers/driver.h"
#include "eap_server/eap.h"
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
#include "ap/dpp_hostapd.h"
#include "fst/fst.h"
#include "config_file.h"
#include "eap_register.h"
#include "ctrl_iface.h"
struct hapd_global {
void **drv_priv;
size_t drv_count;
};
static struct hapd_global global;
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
int level, const char *txt, size_t len)
{
struct hostapd_data *hapd = ctx;
char *format, *module_str;
int maxlen;
int conf_syslog_level, conf_stdout_level;
unsigned int conf_syslog, conf_stdout;
maxlen = len + 100;
format = os_malloc(maxlen);
if (!format)
return;
if (hapd && hapd->conf) {
conf_syslog_level = hapd->conf->logger_syslog_level;
conf_stdout_level = hapd->conf->logger_stdout_level;
conf_syslog = hapd->conf->logger_syslog;
conf_stdout = hapd->conf->logger_stdout;
} else {
conf_syslog_level = conf_stdout_level = 0;
conf_syslog = conf_stdout = (unsigned int) -1;
}
switch (module) {
case HOSTAPD_MODULE_IEEE80211:
module_str = "IEEE 802.11";
break;
case HOSTAPD_MODULE_IEEE8021X:
module_str = "IEEE 802.1X";
break;
case HOSTAPD_MODULE_RADIUS:
module_str = "RADIUS";
break;
case HOSTAPD_MODULE_WPA:
module_str = "WPA";
break;
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
default:
module_str = NULL;
break;
}
if (hapd && hapd->conf && addr)
os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
hapd->conf->iface, MAC2STR(addr),
module_str ? " " : "", module_str ? module_str : "",
txt);
else if (hapd && hapd->conf)
os_snprintf(format, maxlen, "%s:%s%s %s",
hapd->conf->iface, module_str ? " " : "",
module_str ? module_str : "", txt);
else if (addr)
os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
MAC2STR(addr), module_str ? " " : "",
module_str ? module_str : "", txt);
else
os_snprintf(format, maxlen, "%s%s%s",
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);
}
#ifndef CONFIG_NATIVE_WINDOWS
if ((conf_syslog & module) && level >= conf_syslog_level) {
int priority;
switch (level) {
case HOSTAPD_LEVEL_DEBUG_VERBOSE:
case HOSTAPD_LEVEL_DEBUG:
priority = LOG_DEBUG;
break;
case HOSTAPD_LEVEL_INFO:
priority = LOG_INFO;
break;
case HOSTAPD_LEVEL_NOTICE:
priority = LOG_NOTICE;
break;
case HOSTAPD_LEVEL_WARNING:
priority = LOG_WARNING;
break;
default:
priority = LOG_INFO;
break;
}
syslog(priority, "%s", format);
}
#endif /* CONFIG_NATIVE_WINDOWS */
os_free(format);
}
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
/**
* hostapd_driver_init - Preparate driver interface
*/
static int hostapd_driver_init(struct hostapd_iface *iface)
{
struct wpa_init_params params;
size_t i;
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_bss_config *conf = hapd->conf;
u8 *b = conf->bssid;
struct wpa_driver_capa capa;
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
return -1;
}
/* Initialize the driver interface */
if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
b = NULL;
os_memset(&params, 0, sizeof(params));
for (i = 0; wpa_drivers[i]; i++) {
if (wpa_drivers[i] != hapd->driver)
continue;
if (global.drv_priv[i] == NULL &&
wpa_drivers[i]->global_init) {
global.drv_priv[i] =
wpa_drivers[i]->global_init(iface->interfaces);
if (global.drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize "
"driver '%s'",
wpa_drivers[i]->name);
return -1;
}
}
params.global_priv = global.drv_priv[i];
break;
}
params.bssid = b;
params.ifname = hapd->conf->iface;
params.driver_params = hapd->iconf->driver_params;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
if (params.bridge == NULL)
return -1;
for (i = 0; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
if (bss->conf->bridge[0])
params.bridge[i] = bss->conf->bridge;
}
params.own_addr = hapd->own_addr;
hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
os_free(params.bridge);
if (hapd->drv_priv == NULL) {
wpa_printf(MSG_ERROR, "%s driver initialization failed.",
hapd->driver->name);
hapd->driver = NULL;
return -1;
}
if (hapd->driver->get_capa &&
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
iface->drv_flags2 = capa.flags2;
iface->probe_resp_offloads = capa.probe_resp_offloads;
/*
* Use default extended capa values from per-radio information
*/
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
/*
* Override extended capa with per-interface type (AP), if
* available from the driver.
*/
hostapd_get_ext_capa(iface);
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
if (triggs && hapd->driver->set_wowlan) {
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
wpa_printf(MSG_ERROR, "set_wowlan failed");
}
os_free(triggs);
}
return 0;
}
/**
* hostapd_interface_init - Read configuration file and init BSS data
*
* This function is used to parse configuration file for a full interface (one
* or more BSSes sharing the same radio) and allocate memory for the BSS
* interfaces. No actual driver operations are started.
*/
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
const char *config_fname, int debug)
{
struct hostapd_iface *iface;
int k;
wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
if (if_name) {
os_strlcpy(iface->conf->bss[0]->iface, if_name,
sizeof(iface->conf->bss[0]->iface));
}
iface->interfaces = interfaces;
for (k = 0; k < debug; k++) {
if (iface->bss[0]->conf->logger_stdout_level > 0)
iface->bss[0]->conf->logger_stdout_level--;
}
if (iface->conf->bss[0]->iface[0] == '\0' &&
!hostapd_drv_none(iface->bss[0])) {
wpa_printf(MSG_ERROR,
"Interface name not specified in %s, nor by '-i' parameter",
config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
}
return iface;
}
/**
* handle_term - SIGINT and SIGTERM handler to terminate hostapd process
*/
static void handle_term(int sig, void *signal_ctx)
{
wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
eloop_terminate();
}
#ifndef CONFIG_NATIVE_WINDOWS
static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
{
if (hostapd_reload_config(iface) < 0) {
wpa_printf(MSG_WARNING, "Failed to read new configuration "
"file - continuing with old.");
}
return 0;
}
/**
* handle_reload - SIGHUP handler to reload configuration
*/
static void handle_reload(int sig, void *signal_ctx)
{
struct hapd_interfaces *interfaces = signal_ctx;
wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
sig);
hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
}
static void handle_dump_state(int sig, void *signal_ctx)
{
/* Not used anymore - ignore signal */
}
#endif /* CONFIG_NATIVE_WINDOWS */
static int hostapd_global_init(struct hapd_interfaces *interfaces,
const char *entropy_file)
{
int i;
os_memset(&global, 0, sizeof(global));
hostapd_logger_register_cb(hostapd_logger_cb);
if (eap_server_register_methods()) {
wpa_printf(MSG_ERROR, "Failed to register EAP methods");
return -1;
}
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return -1;
}
interfaces->eloop_initialized = 1;
random_init(entropy_file);
#ifndef CONFIG_NATIVE_WINDOWS
eloop_register_signal(SIGHUP, handle_reload, interfaces);
eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
#endif /* CONFIG_NATIVE_WINDOWS */
eloop_register_signal_terminate(handle_term, interfaces);
#ifndef CONFIG_NATIVE_WINDOWS
openlog("hostapd", 0, LOG_DAEMON);
#endif /* CONFIG_NATIVE_WINDOWS */
for (i = 0; wpa_drivers[i]; i++)
global.drv_count++;
if (global.drv_count == 0) {
wpa_printf(MSG_ERROR, "No drivers enabled");
return -1;
}
global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
if (global.drv_priv == NULL)
return -1;
return 0;
}
static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
{
int i;
for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
if (!global.drv_priv[i])
continue;
wpa_drivers[i]->global_deinit(global.drv_priv[i]);
}
os_free(global.drv_priv);
global.drv_priv = NULL;
#ifdef EAP_SERVER_TNC
tncs_global_deinit();
#endif /* EAP_SERVER_TNC */
random_deinit();
if (eloop_initialized)
eloop_destroy();
#ifndef CONFIG_NATIVE_WINDOWS
closelog();
#endif /* CONFIG_NATIVE_WINDOWS */
eap_server_unregister_methods();
os_daemonize_terminate(pid_file);
}
static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
const char *pid_file)
{
#ifdef EAP_SERVER_TNC
int tnc = 0;
size_t i, k;
for (i = 0; !tnc && i < ifaces->count; i++) {
for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
if (ifaces->iface[i]->bss[0]->conf->tnc) {
tnc++;
break;
}
}
}
if (tnc && tncs_global_init() < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
return -1;
}
#endif /* EAP_SERVER_TNC */
if (daemonize) {
if (os_daemonize(pid_file)) {
wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
if (eloop_sock_requeue()) {
wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
strerror(errno));
return -1;
}
}
eloop_run();
return 0;
}
static void show_version(void)
{
fprintf(stderr,
"hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> "
"and contributors\n",
VERSION_STR);
}
static void usage(void)
{
show_version();
fprintf(stderr,
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
" [-g <global ctrl_iface>] [-G <group>]\\\n"
" [-i <comma-separated list of interface names>]\\\n"
" <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
" -d show more debug messages (-dd for even more)\n"
" -B run daemon in the background\n"
" -e entropy file\n"
" -g global control interface path\n"
" -G group for control interfaces\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_LINUX_TRACING
" -T record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
" -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");
exit(1);
}
static const char * hostapd_msg_ifname_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
if (hapd && hapd->conf)
return hapd->conf->iface;
return NULL;
}
static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
const char *path)
{
#ifndef CONFIG_CTRL_IFACE_UDP
char *pos;
#endif /* !CONFIG_CTRL_IFACE_UDP */
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = os_strdup(path);
if (interfaces->global_iface_path == NULL)
return -1;
#ifndef CONFIG_CTRL_IFACE_UDP
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "No '/' in the global control interface "
"file");
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
return -1;
}
*pos = '\0';
interfaces->global_iface_name = pos + 1;
#endif /* !CONFIG_CTRL_IFACE_UDP */
return 0;
}
static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
const char *group)
{
#ifndef CONFIG_NATIVE_WINDOWS
struct group *grp;
grp = getgrnam(group);
if (grp == NULL) {
wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
return -1;
}
interfaces->ctrl_iface_group = grp->gr_gid;
#endif /* CONFIG_NATIVE_WINDOWS */
return 0;
}
static int hostapd_get_interface_names(char ***if_names,
size_t *if_names_size,
char *arg)
{
char *if_name, *tmp, **nnames;
size_t i;
if (!arg)
return -1;
if_name = strtok_r(arg, ",", &tmp);
while (if_name) {
nnames = os_realloc_array(*if_names, 1 + *if_names_size,
sizeof(char *));
if (!nnames)
goto fail;
*if_names = nnames;
(*if_names)[*if_names_size] = os_strdup(if_name);
if (!(*if_names)[*if_names_size])
goto fail;
(*if_names_size)++;
if_name = strtok_r(NULL, ",", &tmp);
}
return 0;
fail:
for (i = 0; i < *if_names_size; i++)
os_free((*if_names)[i]);
os_free(*if_names);
*if_names = NULL;
*if_names_size = 0;
return -1;
}
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
{
u8 addr[ETH_ALEN];
u8 uuid[UUID_LEN];
char buf[100];
if (hwaddr_aton(txt_addr, addr) < 0)
return -1;
uuid_gen_mac_addr(addr, uuid);
if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
return -1;
printf("%s\n", buf);
return 0;
}
#endif /* CONFIG_WPS */
#ifndef HOSTAPD_CLEANUP_INTERVAL
#define HOSTAPD_CLEANUP_INTERVAL 10
#endif /* HOSTAPD_CLEANUP_INTERVAL */
static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
{
hostapd_periodic_iface(iface);
return 0;
}
/* Periodic cleanup tasks */
static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
{
struct hapd_interfaces *interfaces = eloop_ctx;
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
hostapd_periodic, interfaces, NULL);
hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
}
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
int ret = 1;
size_t i, j;
int c, debug = 0, daemonize = 0;
char *pid_file = NULL;
const char *log_file = NULL;
const char *entropy_file = NULL;
char **bss_config = NULL, **tmp_bss;
size_t num_bss_configs = 0;
#ifdef CONFIG_DEBUG_LINUX_TRACING
int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
int start_ifaces_in_sync = 0;
char **if_names = NULL;
size_t if_names_size = 0;
#ifdef CONFIG_DPP
struct dpp_global_config dpp_conf;
#endif /* CONFIG_DPP */
if (os_program_init())
return -1;
os_memset(&interfaces, 0, sizeof(interfaces));
interfaces.reload_config = hostapd_reload_config;
interfaces.config_read_cb = hostapd_config_read;
interfaces.for_each_interface = hostapd_for_each_interface;
interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
interfaces.driver_init = hostapd_driver_init;
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
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
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
dpp_conf.cb_ctx = &interfaces;
#ifdef CONFIG_DPP2
dpp_conf.remove_bi = hostapd_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp)
return -1;
#endif /* CONFIG_DPP */
for (;;) {
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
if (c < 0)
break;
switch (c) {
case 'h':
usage();
break;
case 'd':
debug++;
if (wpa_debug_level > 0)
wpa_debug_level--;
break;
case 'B':
daemonize++;
break;
case 'e':
entropy_file = optarg;
break;
case 'f':
log_file = optarg;
break;
case 'K':
wpa_debug_show_keys++;
break;
case 'P':
os_free(pid_file);
pid_file = os_rel2abs_path(optarg);
break;
case 't':
wpa_debug_timestamp++;
break;
#ifdef CONFIG_DEBUG_LINUX_TRACING
case 'T':
enable_trace_dbg = 1;
break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 'v':
show_version();
exit(1);
break;
case 'g':
if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
return -1;
break;
case 'G':
if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
return -1;
break;
case 'b':
tmp_bss = os_realloc_array(bss_config,
num_bss_configs + 1,
sizeof(char *));
if (tmp_bss == NULL)
goto out;
bss_config = tmp_bss;
bss_config[num_bss_configs++] = optarg;
break;
#ifdef CONFIG_DEBUG_SYSLOG
case 's':
wpa_debug_syslog = 1;
break;
#endif /* CONFIG_DEBUG_SYSLOG */
case 'S':
start_ifaces_in_sync = 1;
break;
#ifdef CONFIG_WPS
case 'u':
return gen_uuid(optarg);
#endif /* CONFIG_WPS */
case 'i':
if (hostapd_get_interface_names(&if_names,
&if_names_size, optarg))
goto out;
break;
default:
usage();
break;
}
}
if (optind == argc && interfaces.global_iface_path == NULL &&
num_bss_configs == 0)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
if (log_file)
wpa_debug_open_file(log_file);
if (!log_file && !wpa_debug_syslog)
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();
if (tret) {
wpa_printf(MSG_ERROR, "Failed to enable trace logging");
return -1;
}
}
#endif /* CONFIG_DEBUG_LINUX_TRACING */
interfaces.count = argc - optind;
if (interfaces.count || num_bss_configs) {
interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
sizeof(struct hostapd_iface *));
if (interfaces.iface == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
return -1;
}
}
if (hostapd_global_init(&interfaces, entropy_file)) {
wpa_printf(MSG_ERROR, "Failed to initialize global context");
return -1;
}
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
hostapd_periodic, &interfaces, NULL);
if (fst_global_init()) {
wpa_printf(MSG_ERROR,
"Failed to initialize global FST context");
goto out;
}
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
if (!fst_global_add_ctrl(fst_ctrl_cli))
wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
char *if_name = NULL;
if (i < if_names_size)
if_name = if_names[i];
interfaces.iface[i] = hostapd_interface_init(&interfaces,
if_name,
argv[optind + i],
debug);
if (!interfaces.iface[i]) {
wpa_printf(MSG_ERROR, "Failed to initialize interface");
goto out;
}
if (start_ifaces_in_sync)
interfaces.iface[i]->need_to_start_in_sync = 1;
}
/* Allocate and parse configuration for per-BSS files */
for (i = 0; i < num_bss_configs; i++) {
struct hostapd_iface *iface;
char *fname;
wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
fname = os_strchr(bss_config[i], ':');
if (fname == NULL) {
wpa_printf(MSG_ERROR,
"Invalid BSS config identifier '%s'",
bss_config[i]);
goto out;
}
*fname++ = '\0';
iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
fname, debug);
if (iface == NULL)
goto out;
for (j = 0; j < interfaces.count; j++) {
if (interfaces.iface[j] == iface)
break;
}
if (j == interfaces.count) {
struct hostapd_iface **tmp;
tmp = os_realloc_array(interfaces.iface,
interfaces.count + 1,
sizeof(struct hostapd_iface *));
if (tmp == NULL) {
hostapd_interface_deinit_free(iface);
goto out;
}
interfaces.iface = tmp;
interfaces.iface[interfaces.count++] = iface;
}
}
/*
* Enable configured interfaces. Depending on channel configuration,
* this may complete full initialization before returning or use a
* callback mechanism to complete setup in case of operations like HT
* co-ex scans, ACS, or DFS are needed to determine channel parameters.
* In such case, the interface will be enabled from eloop context within
* hostapd_global_run().
*/
interfaces.terminate_on_error = interfaces.count;
for (i = 0; i < interfaces.count; i++) {
if (hostapd_driver_init(interfaces.iface[i]) ||
hostapd_setup_interface(interfaces.iface[i]))
goto out;
}
hostapd_global_ctrl_iface_init(&interfaces);
if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
wpa_printf(MSG_ERROR, "Failed to start eloop");
goto out;
}
ret = 0;
out:
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++) {
if (!interfaces.iface[i])
continue;
interfaces.iface[i]->driver_ap_teardown =
!!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]);
interfaces.iface[i] = NULL;
}
os_free(interfaces.iface);
interfaces.iface = NULL;
interfaces.count = 0;
#ifdef CONFIG_DPP
dpp_global_deinit(interfaces.dpp);
#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();
os_free(bss_config);
for (i = 0; i < if_names_size; i++)
os_free(if_names[i]);
os_free(if_names);
fst_global_deinit();
os_program_deinit();
return ret;
}
-47
View File
@@ -1,47 +0,0 @@
/*
* hostapd - Plaintext password to NtPasswordHash
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/ms_funcs.h"
int main(int argc, char *argv[])
{
unsigned char password_hash[16];
size_t i;
char *password, buf[64], *pos;
if (argc > 1)
password = argv[1];
else {
if (fgets(buf, sizeof(buf), stdin) == NULL) {
printf("Failed to read password\n");
return 1;
}
buf[sizeof(buf) - 1] = '\0';
pos = buf;
while (*pos != '\0') {
if (*pos == '\r' || *pos == '\n') {
*pos = '\0';
break;
}
pos++;
}
password = buf;
}
if (nt_password_hash((u8 *) password, strlen(password), password_hash))
return -1;
for (i = 0; i < sizeof(password_hash); i++)
printf("%02x", password_hash[i]);
printf("\n");
return 0;
}
-196
View File
@@ -1,196 +0,0 @@
/*
* SAE-PK password/modifier generator
* Copyright (c) 2020, The Linux Foundation
*
* 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/base64.h"
#include "crypto/crypto.h"
#include "common/sae.h"
int main(int argc, char *argv[])
{
char *der = NULL;
size_t der_len;
struct crypto_ec_key *key = NULL;
struct wpabuf *pub = NULL;
u8 *data = NULL, *m;
size_t data_len;
char *b64 = NULL, *pw = NULL, *pos, *src;
int sec, j;
int ret = -1;
u8 hash[SAE_MAX_HASH_LEN];
char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
u8 pw_base_bin[SAE_MAX_HASH_LEN];
u8 *dst;
int group;
size_t hash_len;
unsigned long long i, expected;
char m_hex[2 * SAE_PK_M_LEN + 1];
u32 sec_1b, val20;
wpa_debug_level = MSG_INFO;
if (os_program_init() < 0)
goto fail;
if (argc != 4) {
fprintf(stderr,
"usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
goto fail;
}
sec = atoi(argv[2]);
if (sec != 3 && sec != 5) {
fprintf(stderr,
"Invalid Sec value (allowed values: 3 and 5)\n");
goto fail;
}
sec_1b = sec == 3;
expected = 1;
for (j = 0; j < sec; j++)
expected *= 256;
der = os_readfile(argv[1], &der_len);
if (!der) {
fprintf(stderr, "Could not read %s: %s\n",
argv[1], strerror(errno));
goto fail;
}
key = crypto_ec_key_parse_priv((u8 *) der, der_len);
if (!key) {
fprintf(stderr, "Could not parse ECPrivateKey\n");
goto fail;
}
pub = crypto_ec_key_get_subject_public_key(key);
if (!pub) {
fprintf(stderr, "Failed to build SubjectPublicKey\n");
goto fail;
}
group = crypto_ec_key_group(key);
switch (group) {
case 19:
hash_len = 32;
break;
case 20:
hash_len = 48;
break;
case 21:
hash_len = 64;
break;
default:
fprintf(stderr, "Unsupported private key group\n");
goto fail;
}
data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
data = os_malloc(data_len);
if (!data) {
fprintf(stderr, "No memory for data buffer\n");
goto fail;
}
os_memcpy(data, argv[3], os_strlen(argv[3]));
m = data + os_strlen(argv[3]);
if (os_get_random(m, SAE_PK_M_LEN) < 0) {
fprintf(stderr, "Could not generate random Modifier M\n");
goto fail;
}
os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
fprintf(stderr, "Searching for a suitable Modifier M value\n");
for (i = 0;; i++) {
if (sae_hash(hash_len, data, data_len, hash) < 0) {
fprintf(stderr, "Hash failed\n");
goto fail;
}
if (hash[0] == 0 && hash[1] == 0) {
if ((hash[2] & 0xf0) == 0)
fprintf(stderr, "\r%3.2f%%",
100.0 * (double) i / (double) expected);
for (j = 2; j < sec; j++) {
if (hash[j])
break;
}
if (j == sec)
break;
}
inc_byte_array(m, SAE_PK_M_LEN);
}
if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
goto fail;
fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
i + 1, hash_hex);
b64 = base64_encode(der, der_len, NULL);
if (!b64)
goto fail;
src = pos = b64;
while (*src) {
if (*src != '\n')
*pos++ = *src;
src++;
}
*pos = '\0';
/* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
* one. */
os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
dst = pw_base_bin;
for (j = 0; j < 8 * (int) hash_len / 20; j++) {
val20 = sae_pk_get_be19(hash + sec);
val20 |= sec_1b << 19;
sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
if (j & 1) {
*dst |= (val20 >> 16) & 0x0f;
dst++;
*dst++ = (val20 >> 8) & 0xff;
*dst++ = val20 & 0xff;
} else {
*dst++ = (val20 >> 12) & 0xff;
*dst++ = (val20 >> 4) & 0xff;
*dst = (val20 << 4) & 0xf0;
}
}
if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
pw_base_bin, hash_len - sec) >= 0)
fprintf(stderr, "PasswordBase binary data for base32: %s",
hash_hex);
pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
if (!pw)
goto fail;
printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
printf("# Longer passwords can be used for improved security at the cost of usability:\n");
for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
os_free(pw);
pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
if (pw)
printf("# %s\n", pw);
}
ret = 0;
fail:
os_free(der);
wpabuf_free(pub);
crypto_ec_key_deinit(key);
os_free(data);
os_free(b64);
os_free(pw);
os_program_deinit();
return ret;
}
-40
View File
@@ -1,40 +0,0 @@
##### hostapd configuration file ##############################################
# Empty lines and lines starting with # are ignored
# Example configuration file for wired authenticator. See hostapd.conf for
# more details.
interface=eth0
driver=wired
logger_stdout=-1
logger_stdout_level=1
debug=2
dump_file=/tmp/hostapd.dump
ieee8021x=1
eap_reauth_period=3600
use_pae_group_addr=1
##### RADIUS configuration ####################################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
# authentication with external ACL for MAC addresses, and accounting
# The own IP address of the access point (used as NAS-IP-Address)
own_ip_addr=127.0.0.1
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
# a unique to the NAS within the scope of the RADIUS server. For example, a
# fully qualified domain name can be used here.
nas_identifier=ap.example.com
# RADIUS authentication server
auth_server_addr=127.0.0.1
auth_server_port=1812
auth_server_shared_secret=radius
# RADIUS accounting server
acct_server_addr=127.0.0.1
acct_server_port=1813
acct_server_shared_secret=radius
-342
View File
@@ -1,342 +0,0 @@
#!/usr/bin/python
#
# Example nfcpy to hostapd wrapper for WPS NFC operations
# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import os
import sys
import time
import argparse
import nfc
import nfc.ndef
import nfc.llcp
import nfc.handover
import logging
import wpaspy
wpas_ctrl = '/var/run/hostapd'
continue_loop = True
summary_file = None
success_file = None
def summary(txt):
print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
def success_report(txt):
summary(txt)
if success_file:
with open(success_file, 'a') as f:
f.write(txt + "\n")
def wpas_connect():
ifaces = []
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
except OSError as error:
print("Could not find hostapd: ", error)
return None
if len(ifaces) < 1:
print("No hostapd control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
except Exception as e:
pass
return None
def wpas_tag_read(message):
wpas = wpas_connect()
if (wpas == None):
return False
if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
return False
return True
def wpas_get_config_token():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_get_password_token():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("WPS_NFC_TOKEN NDEF")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_get_handover_sel():
wpas = wpas_connect()
if (wpas == None):
return None
ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
if "FAIL" in ret:
return None
return ret.rstrip().decode("hex")
def wpas_report_handover(req, sel):
wpas = wpas_connect()
if (wpas == None):
return None
return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
str(req).encode("hex") + " " +
str(sel).encode("hex"))
class HandoverServer(nfc.handover.HandoverServer):
def __init__(self, llc):
super(HandoverServer, self).__init__(llc)
self.ho_server_processing = False
self.success = False
# override to avoid parser error in request/response.pretty() in nfcpy
# due to new WSC handover format
def _process_request(self, request):
summary("received handover request {}".format(request.type))
response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
if not request.type == 'urn:nfc:wkt:Hr':
summary("not a handover request")
else:
try:
request = nfc.ndef.HandoverRequestMessage(request)
except nfc.ndef.DecodeError as e:
summary("error decoding 'Hr' message: {}".format(e))
else:
response = self.process_request(request)
summary("send handover response {}".format(response.type))
return response
def process_request(self, request):
summary("HandoverServer - request received")
try:
print("Parsed handover request: " + request.pretty())
except Exception as e:
print(e)
print(str(request).encode("hex"))
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel()
if data is None:
summary("Could not get handover select carrier record from hostapd")
continue
print("Handover select carrier record from hostapd:")
print(data.encode("hex"))
if "OK" in wpas_report_handover(carrier.record, data):
success_report("Handover reported successfully")
else:
summary("Handover report rejected")
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
print("Handover select:")
try:
print(sel.pretty())
except Exception as e:
print(e)
print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
return sel
def wps_tag_read(tag):
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to hostapd")
success = wpas_tag_read(tag.ndef.message)
break
else:
summary("Empty tag")
if success:
success_report("Tag read succeeded")
return success
def rdwr_connected_write(tag):
summary("Tag found - writing - " + str(tag))
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
print("Done - remove tag")
global only_one
if only_one:
global continue_loop
continue_loop = False
global write_wait_remove
while write_wait_remove and tag.is_present:
time.sleep(0.1)
def wps_write_config_tag(clf, wait_remove=True):
summary("Write WPS config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_config_token()
if write_data == None:
summary("Could not get WPS config token from hostapd")
return
print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_password_tag(clf, wait_remove=True):
summary("Write WPS password token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_password_token()
if write_data == None:
summary("Could not get WPS password token from hostapd")
return
print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def rdwr_connected(tag):
global only_one, no_wait
summary("Tag connected: " + str(tag))
if tag.ndef:
print("NDEF tag: " + tag.type)
try:
print(tag.ndef.message.pretty())
except Exception as e:
print(e)
success = wps_tag_read(tag)
if only_one and success:
global continue_loop
continue_loop = False
else:
summary("Not an NDEF tag - remove tag")
return True
return not no_wait
def llcp_startup(clf, llc):
print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
print("P2P LLCP connected")
global wait_connection
wait_connection = False
global srv
srv.start()
return True
def main():
clf = nfc.ContactlessFrontend()
parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
action='store_const', dest='loglevel',
help='verbose debug output')
parser.add_argument('-q', const=logging.WARNING, action='store_const',
dest='loglevel', help='be quiet')
parser.add_argument('--only-one', '-1', action='store_true',
help='run only one operation and exit')
parser.add_argument('--no-wait', action='store_true',
help='do not wait for tag to be removed before exiting')
parser.add_argument('--summary',
help='summary file for writing status updates')
parser.add_argument('--success',
help='success file for writing success update')
parser.add_argument('command', choices=['write-config',
'write-password'],
nargs='?')
args = parser.parse_args()
global only_one
only_one = args.only_one
global no_wait
no_wait = args.no_wait
if args.summary:
global summary_file
summary_file = args.summary
if args.success:
global success_file
success_file = args.success
logging.basicConfig(level=args.loglevel)
try:
if not clf.open("usb"):
print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
wps_write_config_tag(clf, wait_remove=not args.no_wait)
raise SystemExit
if args.command == "write-password":
wps_write_password_tag(clf, wait_remove=not args.no_wait)
raise SystemExit
global continue_loop
while continue_loop:
print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
llcp={'on-startup': llcp_startup,
'on-connect': llcp_connected}):
break
except Exception as e:
print("clf.connect failed")
global srv
if only_one and srv and srv.success:
raise SystemExit
except KeyboardInterrupt:
raise SystemExit
finally:
clf.close()
raise SystemExit
if __name__ == '__main__':
main()
+10
View File
@@ -60,6 +60,10 @@ L_CFLAGS += -DEAP_TLS_OPENSSL
L_CFLAGS += -Wno-unused-parameter
ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
L_CFLAGS += -DCONFIG_ANDROID_LOG
L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"'
endif
########################
include $(CLEAR_VARS)
@@ -68,9 +72,15 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libc libcutils
LOCAL_SHARED_LIBRARIES += libcrypto libssl
ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
LOCAL_VENDOR_MODULE := true
LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += liblog
else
#LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_STATIC_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += libicuuc
endif # End of check for platform version
LOCAL_SHARED_LIBRARIES += libcurl
LOCAL_CFLAGS := $(L_CFLAGS)
+5 -32
View File
@@ -11,15 +11,12 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/opensslv.h>
#ifdef OPENSSL_IS_BORINGSSL
#include <openssl/buf.h>
#endif /* OPENSSL_IS_BORINGSSL */
#include <openssl/buffer.h>
#include "common.h"
#include "utils/base64.h"
@@ -220,7 +217,7 @@ typedef struct {
} d;
} AttrOrOID;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
DEFINE_STACK_OF(AttrOrOID)
#endif
@@ -340,30 +337,13 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
if (!csrattrs || ! csrattrs->attrs)
return;
#ifdef OPENSSL_IS_BORINGSSL
num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
csrattrs->attrs));
for (i = 0; i < num; i++) {
AttrOrOID *ao = sk_value(
CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
csrattrs->attrs), i);
switch (ao->type) {
case 0:
add_csrattrs_oid(ctx, ao->d.oid, exts);
break;
case 1:
add_csrattrs_attr(ctx, ao->d.attribute, exts);
break;
}
}
#else /* OPENSSL_IS_BORINGSSL */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
num = sk_AttrOrOID_num(csrattrs->attrs);
#else
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
#endif
for (i = 0; i < num; i++) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
#else
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
@@ -377,7 +357,6 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
break;
}
}
#endif /* OPENSSL_IS_BORINGSSL */
}
@@ -387,7 +366,6 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
{
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa;
X509_REQ *req = NULL;
int ret = -1;
unsigned int val;
@@ -415,16 +393,11 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
EVP_PKEY_CTX_free(pctx);
pctx = NULL;
rsa = EVP_PKEY_get1_RSA(pkey);
if (rsa == NULL)
goto fail;
if (key_pem) {
FILE *f = fopen(key_pem, "wb");
if (f == NULL)
goto fail;
if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL,
NULL)) {
if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
wpa_printf(MSG_INFO, "Could not write private key: %s",
ERR_error_string(ERR_get_error(), NULL));
fclose(f);
+79 -36
View File
@@ -1231,12 +1231,13 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
homeoi, required);
if (required) {
if (set_cred(ctx->ifname, id, "required_roaming_consortium",
homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
if (set_cred_quoted(ctx->ifname, id, "required_home_ois",
homeoi) < 0)
wpa_printf(MSG_INFO,
"Failed to set cred required_home_ois");
} else {
if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
if (set_cred_quoted(ctx->ifname, id, "home_ois", homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred home_ois");
}
xml_node_get_text_free(ctx->xml, homeoi);
@@ -2018,6 +2019,7 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
struct osu_data *osu = NULL, *last = NULL;
size_t osu_count = 0;
char *pos, *end;
int res;
f = fopen(fname, "r");
if (f == NULL) {
@@ -2037,15 +2039,20 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
osu = last;
last = &osu[osu_count++];
memset(last, 0, sizeof(*last));
snprintf(last->bssid, sizeof(last->bssid), "%s",
buf + 13);
res = os_snprintf(last->bssid, sizeof(last->bssid),
"%s", buf + 13);
if (os_snprintf_error(sizeof(last->bssid), res))
break;
continue;
}
if (!last)
continue;
if (strncmp(buf, "uri=", 4) == 0) {
snprintf(last->url, sizeof(last->url), "%s", buf + 4);
res = os_snprintf(last->url, sizeof(last->url),
"%s", buf + 4);
if (os_snprintf_error(sizeof(last->url), res))
break;
continue;
}
@@ -2055,26 +2062,37 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
}
if (strncmp(buf, "osu_ssid=", 9) == 0) {
snprintf(last->osu_ssid, sizeof(last->osu_ssid),
"%s", buf + 9);
res = os_snprintf(last->osu_ssid,
sizeof(last->osu_ssid),
"%s", buf + 9);
if (os_snprintf_error(sizeof(last->osu_ssid), res))
break;
continue;
}
if (strncmp(buf, "osu_ssid2=", 10) == 0) {
snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
"%s", buf + 10);
res = os_snprintf(last->osu_ssid2,
sizeof(last->osu_ssid2),
"%s", buf + 10);
if (os_snprintf_error(sizeof(last->osu_ssid2), res))
break;
continue;
}
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
"%s", buf + 8);
res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
"%s", buf + 8);
if (os_snprintf_error(sizeof(last->osu_nai), res))
break;
continue;
}
if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
"%s", buf + 9);
res = os_snprintf(last->osu_nai2,
sizeof(last->osu_nai2),
"%s", buf + 9);
if (os_snprintf_error(sizeof(last->osu_nai2), res))
break;
continue;
}
@@ -2087,8 +2105,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
continue;
*pos++ = '\0';
txt = &last->friendly_name[last->friendly_name_count++];
snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14);
snprintf(txt->text, sizeof(txt->text), "%s", pos);
res = os_snprintf(txt->lang, sizeof(txt->lang),
"%s", buf + 14);
if (os_snprintf_error(sizeof(txt->lang), res))
break;
res = os_snprintf(txt->text, sizeof(txt->text),
"%s", pos);
if (os_snprintf_error(sizeof(txt->text), res))
break;
}
if (strncmp(buf, "desc=", 5) == 0) {
@@ -2100,8 +2124,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
continue;
*pos++ = '\0';
txt = &last->serv_desc[last->serv_desc_count++];
snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5);
snprintf(txt->text, sizeof(txt->text), "%s", pos);
res = os_snprintf(txt->lang, sizeof(txt->lang),
"%s", buf + 5);
if (os_snprintf_error(sizeof(txt->lang), res))
break;
res = os_snprintf(txt->text, sizeof(txt->text),
"%s", pos);
if (os_snprintf_error(sizeof(txt->text), res))
break;
}
if (strncmp(buf, "icon=", 5) == 0) {
@@ -2124,23 +2154,30 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
if (!end)
continue;
*end = '\0';
snprintf(icon->lang, sizeof(icon->lang), "%s", pos);
res = os_snprintf(icon->lang, sizeof(icon->lang),
"%s", pos);
if (os_snprintf_error(sizeof(icon->lang), res))
break;
pos = end + 1;
end = strchr(pos, ':');
if (end)
*end = '\0';
snprintf(icon->mime_type, sizeof(icon->mime_type),
"%s", pos);
if (!pos)
res = os_snprintf(icon->mime_type,
sizeof(icon->mime_type), "%s", pos);
if (os_snprintf_error(sizeof(icon->mime_type), res))
break;
if (!end)
continue;
pos = end + 1;
end = strchr(pos, ':');
if (end)
*end = '\0';
snprintf(icon->filename, sizeof(icon->filename),
"%s", pos);
res = os_snprintf(icon->filename,
sizeof(icon->filename), "%s", pos);
if (os_snprintf_error(sizeof(icon->filename), res))
break;
continue;
}
}
@@ -2911,20 +2948,27 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
int found;
char *host = NULL;
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
!ctx->no_osu_cert_validation, ctx->server_url);
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
!ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
ctx->server_url);
host = get_hostname(ctx->server_url);
if (ctx->no_osu_cert_validation && cert->url)
host = get_hostname(cert->url);
else
host = get_hostname(ctx->server_url);
for (i = 0; i < ctx->server_dnsname_count; i++)
os_free(ctx->server_dnsname[i]);
os_free(ctx->server_dnsname);
ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *));
ctx->server_dnsname_count = 0;
if (!ctx->no_osu_cert_validation) {
for (i = 0; i < ctx->server_dnsname_count; i++)
os_free(ctx->server_dnsname[i]);
os_free(ctx->server_dnsname);
ctx->server_dnsname = os_calloc(cert->num_dnsname,
sizeof(char *));
ctx->server_dnsname_count = 0;
}
found = 0;
for (i = 0; i < cert->num_dnsname; i++) {
if (ctx->server_dnsname) {
if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
ctx->server_dnsname[ctx->server_dnsname_count] =
os_strdup(cert->dnsname[i]);
if (ctx->server_dnsname[ctx->server_dnsname_count])
@@ -3249,7 +3293,6 @@ int main(int argc, char *argv[])
default:
usage();
exit(0);
break;
}
}
-1
View File
@@ -564,7 +564,6 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
free(id);
return -1;
}
return 0;
}
if (strcasecmp(name, "uploadMO") == 0) {
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae pasn radius rsn_supp tls utils wps
SUBDIRS += fst
all:
+471 -97
View File
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/list.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
@@ -75,7 +76,7 @@
*
* This corresponds to:
* ---
* (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
* (busy time - tx time) / (active time - tx time) * 2^(chan_nf - band_min_nf)
* ---
*
* The coefficient of 2 reflects the way power in "far-field"
@@ -92,7 +93,7 @@
* calculated easily.
* ---
* (busy time - tx time) / (active time - tx time) *
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
* 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
* ---
*
* However to account for cases where busy/rx time is 0 (channel load is then
@@ -100,7 +101,7 @@
* channel with lower noise floor is preferred. The equation becomes:
* ---
* 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
* 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
* 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
* ---
*
* All this "interference factor" is purely subjective and only time
@@ -241,9 +242,73 @@
* [1] http://en.wikipedia.org/wiki/Near_and_far_field
*/
enum bw_type {
ACS_BW40,
ACS_BW80,
ACS_BW160,
ACS_BW320_1,
ACS_BW320_2,
};
struct bw_item {
int first;
int last;
int center_chan;
};
static const struct bw_item bw_40[] = {
{ 5180, 5200, 38 }, { 5220, 5240, 46 }, { 5260, 5280, 54 },
{ 5300, 5320, 62 }, { 5500, 5520, 102 }, { 5540, 5560, 110 },
{ 5580, 5600, 118 }, { 5620, 5640, 126 }, { 5660, 5680, 134 },
{ 5700, 5720, 142 }, { 5745, 5765, 151 }, { 5785, 5805, 159 },
{ 5825, 5845, 167 }, { 5865, 5885, 175 },
{ 5955, 5975, 3 }, { 5995, 6015, 11 }, { 6035, 6055, 19 },
{ 6075, 6095, 27 }, { 6115, 6135, 35 }, { 6155, 6175, 43 },
{ 6195, 6215, 51 }, { 6235, 6255, 59 }, { 6275, 6295, 67 },
{ 6315, 6335, 75 }, { 6355, 6375, 83 }, { 6395, 6415, 91 },
{ 6435, 6455, 99 }, { 6475, 6495, 107 }, { 6515, 6535, 115 },
{ 6555, 6575, 123 }, { 6595, 6615, 131 }, { 6635, 6655, 139 },
{ 6675, 6695, 147 }, { 6715, 6735, 155 }, { 6755, 6775, 163 },
{ 6795, 6815, 171 }, { 6835, 6855, 179 }, { 6875, 6895, 187 },
{ 6915, 6935, 195 }, { 6955, 6975, 203 }, { 6995, 7015, 211 },
{ 7035, 7055, 219 }, { 7075, 7095, 227}, { -1, -1, -1 }
};
static const struct bw_item bw_80[] = {
{ 5180, 5240, 42 }, { 5260, 5320, 58 }, { 5500, 5560, 106 },
{ 5580, 5640, 122 }, { 5660, 5720, 138 }, { 5745, 5805, 155 },
{ 5825, 5885, 171},
{ 5955, 6015, 7 }, { 6035, 6095, 23 }, { 6115, 6175, 39 },
{ 6195, 6255, 55 }, { 6275, 6335, 71 }, { 6355, 6415, 87 },
{ 6435, 6495, 103 }, { 6515, 6575, 119 }, { 6595, 6655, 135 },
{ 6675, 6735, 151 }, { 6755, 6815, 167 }, { 6835, 6895, 183 },
{ 6915, 6975, 199 }, { 6995, 7055, 215 }, { -1, -1, -1 }
};
static const struct bw_item bw_160[] = {
{ 5180, 5320, 50 }, { 5500, 5640, 114 }, { 5745, 5885, 163 },
{ 5955, 6095, 15 }, { 6115, 6255, 47 }, { 6275, 6415, 79 },
{ 6435, 6575, 111 }, { 6595, 6735, 143 },
{ 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 }
};
static const struct bw_item bw_320_1[] = {
{ 5955, 6255, 31 }, { 6275, 6575, 95 }, { 6595, 6895, 159 },
{ -1, -1, -1 }
};
static const struct bw_item bw_320_2[] = {
{ 6115, 6415, 63 }, { 6435, 6735, 127 }, { 6755, 7055, 191 },
{ -1, -1, -1 }
};
static const struct bw_item *bw_desc[] = {
[ACS_BW40] = bw_40,
[ACS_BW80] = bw_80,
[ACS_BW160] = bw_160,
[ACS_BW320_1] = bw_320_1,
[ACS_BW320_2] = bw_320_2,
};
static int acs_request_scan(struct hostapd_iface *iface);
static int acs_survey_is_sufficient(struct freq_survey *survey);
static void acs_scan_retry(void *eloop_data, void *user_data);
static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@@ -275,6 +340,7 @@ static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
dl_list_init(&chan->survey_list);
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
chan->punct_bitmap = 0;
}
}
@@ -288,6 +354,8 @@ void acs_cleanup(struct hostapd_iface *iface)
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
iface->acs_num_retries = 0;
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
}
@@ -370,48 +438,31 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
}
static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
static bool acs_usable_bw_chan(const struct hostapd_channel_data *chan,
enum bw_type bw)
{
const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620,
5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035,
6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355,
6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675,
6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995,
7035, 7075 };
unsigned int i;
unsigned int i = 0;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->freq == allowed[i])
return 1;
while (bw_desc[bw][i].first != -1) {
if (chan->freq == bw_desc[bw][i].first)
return true;
i++;
}
return 0;
return false;
}
static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
static int acs_get_bw_center_chan(int freq, enum bw_type bw)
{
const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035,
6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
6755, 6835, 6915, 6995 };
unsigned int i;
unsigned int i = 0;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->freq == allowed[i])
return 1;
return 0;
}
static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755,
6915 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->freq == allowed[i])
return 1;
while (bw_desc[bw][i].first != -1) {
if (freq >= bw_desc[bw][i].first &&
freq <= bw_desc[bw][i].last)
return bw_desc[bw][i].center_chan;
i++;
}
return 0;
}
@@ -420,19 +471,24 @@ static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
wpa_printf(MSG_INFO,
"ACS: Survey for freq %d is missing noise floor",
survey->freq);
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
wpa_printf(MSG_INFO,
"ACS: Survey for freq %d is missing channel time",
survey->freq);
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
!(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
wpa_printf(MSG_INFO,
"ACS: Survey is missing RX and busy time (at least one is required)");
"ACS: Survey for freq %d is missing RX and busy time (at least one is required)",
survey->freq);
return 0;
}
@@ -455,7 +511,7 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
}
if (ret == -1)
ret = 1; /* no survey list entries */
ret = 0; /* no survey list entries */
if (!ret) {
wpa_printf(MSG_INFO,
@@ -540,6 +596,10 @@ static void acs_survey_mode_interference_factor(
if (!acs_usable_chan(chan))
continue;
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
iface->conf->acs_exclude_dfs)
continue;
if (!is_in_chanlist(iface, chan))
continue;
@@ -549,6 +609,10 @@ static void acs_survey_mode_interference_factor(
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
iface->conf->country[2] == 0x4f)
continue;
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -594,6 +658,26 @@ acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
}
static enum hostapd_hw_mode
acs_find_mode(struct hostapd_iface *iface, int freq)
{
int i;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->num_hw_features; i++) {
mode = &iface->hw_features[i];
if (!hostapd_hw_skip_mode(iface, mode)) {
chan = acs_find_chan_mode(mode, freq);
if (chan)
return mode->mode;
}
}
return HOSTAPD_MODE_IEEE80211ANY;
}
static struct hostapd_channel_data *
acs_find_chan(struct hostapd_iface *iface, int freq)
{
@@ -644,6 +728,98 @@ static int is_common_24ghz_chan(int chan)
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
#ifdef CONFIG_IEEE80211BE
static void acs_update_puncturing_bitmap(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode, u32 bw,
int n_chans,
struct hostapd_channel_data *chan,
long double factor,
int index_primary)
{
struct hostapd_config *conf = iface->conf;
struct hostapd_channel_data *adj_chan = NULL, *first_chan = chan;
int i;
long double threshold;
/*
* If threshold is 0 or user configured puncturing pattern is
* available then don't add additional puncturing.
*/
if (!conf->punct_acs_threshold || conf->punct_bitmap)
return;
if (is_24ghz_mode(mode->mode) || bw < 80)
return;
threshold = factor * conf->punct_acs_threshold / 100;
for (i = 0; i < n_chans; i++) {
int adj_freq;
if (i == index_primary)
continue; /* Cannot puncture primary channel */
if (i > index_primary)
adj_freq = chan->freq + (i - index_primary) * 20;
else
adj_freq = chan->freq - (index_primary - i) * 20;
adj_chan = acs_find_chan(iface, adj_freq);
if (!adj_chan) {
chan->punct_bitmap = 0;
return;
}
if (i == 0)
first_chan = adj_chan;
if (adj_chan->interference_factor > threshold)
chan->punct_bitmap |= BIT(i);
}
if (!is_punct_bitmap_valid(bw, (chan->freq - first_chan->freq) / 20,
chan->punct_bitmap))
chan->punct_bitmap = 0;
}
#endif /* CONFIG_IEEE80211BE */
static bool
acs_usable_bw320_chan(struct hostapd_iface *iface,
struct hostapd_channel_data *chan, int *bw320_offset)
{
const char *bw320_str[] = { "320 MHz", "320 MHz-1", "320 MHz-2" };
int conf_bw320_offset = hostapd_get_bw320_offset(iface->conf);
*bw320_offset = 0;
switch (conf_bw320_offset) {
case 1:
if (acs_usable_bw_chan(chan, ACS_BW320_1))
*bw320_offset = 1;
break;
case 2:
if (acs_usable_bw_chan(chan, ACS_BW320_2))
*bw320_offset = 2;
break;
case 0:
default:
conf_bw320_offset = 0;
if (acs_usable_bw_chan(chan, ACS_BW320_1))
*bw320_offset = 1;
else if (acs_usable_bw_chan(chan, ACS_BW320_2))
*bw320_offset = 2;
break;
}
if (!*bw320_offset)
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for %s bandwidth",
chan->chan, bw320_str[conf_bw320_offset]);
return *bw320_offset != 0;
}
static void
acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode,
@@ -652,13 +828,21 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_channel_data **ideal_chan,
long double *ideal_factor)
{
struct hostapd_channel_data *chan, *adj_chan = NULL;
struct hostapd_channel_data *chan, *adj_chan = NULL, *best;
long double factor;
int i, j;
int bw320_offset = 0, ideal_bw320_offset = 0;
unsigned int k;
int secondary_channel = 1, freq_offset;
#ifdef CONFIG_IEEE80211BE
int index_primary = 0;
#endif /* CONFIG_IEEE80211BE */
if (is_24ghz_mode(mode->mode))
secondary_channel = iface->conf->secondary_channel;
for (i = 0; i < mode->num_channels; i++) {
double total_weight;
double total_weight = 0;
struct acs_bias *bias, tmp_bias;
chan = &mode->channels[i];
@@ -666,10 +850,20 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
* primary until more sophisticated channel selection is
* implemented. */
* implemented.
*
* If this implementation is changed to allow any channel in
* the bandwidth to be the primary one, the last parameter to
* acs_update_puncturing_bitmap() should be changed to the index
* of the primary channel
*/
if (!chan_pri_allowed(chan))
continue;
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
iface->conf->acs_exclude_dfs)
continue;
if (!is_in_chanlist(iface, chan))
continue;
@@ -679,7 +873,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
if (!chan_bw_allowed(chan, bw, 1, 1)) {
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
iface->conf->country[2] == 0x4f)
continue;
if (!chan_bw_allowed(chan, bw, secondary_channel != -1, 1)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported",
chan->chan, bw);
@@ -692,7 +890,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
((iface->conf->ieee80211n &&
iface->conf->secondary_channel) ||
is_6ghz_freq(chan->freq)) &&
!acs_usable_bw40_chan(chan)) {
!acs_usable_bw_chan(chan, ACS_BW40)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
chan->chan);
@@ -700,10 +898,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
(iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
iface->conf->ieee80211be)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ &&
!acs_usable_bw80_chan(chan)) {
CONF_OPER_CHWIDTH_80MHZ &&
!acs_usable_bw_chan(chan, ACS_BW80)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
chan->chan);
@@ -711,8 +910,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_160MHZ &&
!acs_usable_bw160_chan(chan)) {
CONF_OPER_CHWIDTH_160MHZ &&
!acs_usable_bw_chan(chan, ACS_BW160)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
chan->chan);
@@ -720,13 +919,25 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
}
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211be) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CONF_OPER_CHWIDTH_320MHZ &&
!acs_usable_bw320_chan(iface, chan, &bw320_offset))
continue;
}
factor = 0;
if (acs_usable_chan(chan))
best = NULL;
if (acs_usable_chan(chan)) {
factor = chan->interference_factor;
total_weight = 1;
total_weight = 1;
best = chan;
}
for (j = 1; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
adj_chan = acs_find_chan(iface, chan->freq +
j * secondary_channel * 20);
if (!adj_chan)
break;
@@ -737,10 +948,16 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
break;
}
if (acs_usable_chan(adj_chan)) {
factor += adj_chan->interference_factor;
total_weight += 1;
}
if (!acs_usable_chan(adj_chan))
continue;
factor += adj_chan->interference_factor;
total_weight += 1;
/* find the best channel in this segment */
if (!best || adj_chan->interference_factor <
best->interference_factor)
best = adj_chan;
}
if (j != n_chans) {
@@ -749,12 +966,29 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
continue;
}
/* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less
* crowded primary channel if one was found in the segment */
if (iface->current_mode &&
iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
best && chan != best) {
wpa_printf(MSG_DEBUG,
"ACS: promoting channel %d over %d (less interference %Lg/%Lg)",
best->chan, chan->chan,
chan->interference_factor,
best->interference_factor);
#ifdef CONFIG_IEEE80211BE
index_primary = (chan->freq - best->freq) / 20;
#endif /* CONFIG_IEEE80211BE */
chan = best;
}
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) {
freq_offset = j * 20 * secondary_channel;
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
freq_offset - 5);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -762,7 +996,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 10);
freq_offset - 10);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_NEXT_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -770,7 +1004,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 5);
freq_offset + 5);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -778,7 +1012,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 10);
freq_offset + 10);
if (adj_chan && acs_usable_chan(adj_chan)) {
factor += ACS_NEXT_ADJ_WEIGHT *
adj_chan->interference_factor;
@@ -787,6 +1021,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
}
}
if (total_weight == 0)
continue;
factor /= total_weight;
bias = NULL;
@@ -817,14 +1054,32 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface,
if (acs_usable_chan(chan) &&
(!*ideal_chan || factor < *ideal_factor)) {
/* Reset puncturing bitmap for the previous ideal
* channel */
if (*ideal_chan)
(*ideal_chan)->punct_bitmap = 0;
*ideal_factor = factor;
*ideal_chan = chan;
ideal_bw320_offset = bw320_offset;
#ifdef CONFIG_IEEE80211BE
if (iface->conf->ieee80211be)
acs_update_puncturing_bitmap(iface, mode, bw,
n_chans, chan,
factor,
index_primary);
#endif /* CONFIG_IEEE80211BE */
}
/* This channel would at least be usable */
if (!(*rand_chan))
if (!(*rand_chan)) {
*rand_chan = chan;
ideal_bw320_offset = bw320_offset;
}
}
hostapd_set_and_check_bw320_offset(iface->conf, ideal_bw320_offset);
}
@@ -851,26 +1106,24 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
goto bw_selected;
}
/* TODO: HT40- support */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel == -1) {
wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
return NULL;
}
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel)
n_chans = 2;
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
iface->conf->ieee80211be) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_80MHZ:
case CONF_OPER_CHWIDTH_80MHZ:
n_chans = 4;
break;
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
n_chans = 8;
break;
case CONF_OPER_CHWIDTH_320MHZ:
n_chans = 16;
break;
default:
break;
}
}
@@ -893,6 +1146,13 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
if (ideal_chan) {
wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
ideal_chan->chan, ideal_chan->freq, ideal_factor);
#ifdef CONFIG_IEEE80211BE
if (iface->conf->punct_acs_threshold)
wpa_printf(MSG_DEBUG, "ACS: RU puncturing bitmap 0x%x",
ideal_chan->punct_bitmap);
#endif /* CONFIG_IEEE80211BE */
return ideal_chan;
}
@@ -900,32 +1160,78 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
static void acs_adjust_secondary(struct hostapd_iface *iface)
{
unsigned int i;
/* When working with bandwidth over 20 MHz on the 5 GHz or 6 GHz band,
* ACS can return a secondary channel which is not the first channel of
* the segment and we need to adjust. */
if (!iface->conf->secondary_channel ||
acs_find_mode(iface, iface->freq) != HOSTAPD_MODE_IEEE80211A)
return;
wpa_printf(MSG_DEBUG,
"ACS: Adjusting HT/VHT/HE/EHT secondary frequency");
for (i = 0; bw_desc[ACS_BW40][i].first != -1; i++) {
if (iface->freq == bw_desc[ACS_BW40][i].first)
iface->conf->secondary_channel = 1;
else if (iface->freq == bw_desc[ACS_BW40][i].last)
iface->conf->secondary_channel = -1;
}
}
static void acs_adjust_center_freq(struct hostapd_iface *iface)
{
int offset;
int center;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency");
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
case CONF_OPER_CHWIDTH_USE_HT:
if (iface->conf->secondary_channel &&
iface->freq >= 2400 && iface->freq < 2500)
center = iface->conf->channel +
2 * iface->conf->secondary_channel;
else if (iface->conf->secondary_channel)
center = acs_get_bw_center_chan(iface->freq, ACS_BW40);
else
center = iface->conf->channel;
break;
case CHANWIDTH_80MHZ:
offset = 6;
case CONF_OPER_CHWIDTH_80MHZ:
center = acs_get_bw_center_chan(iface->freq, ACS_BW80);
break;
case CHANWIDTH_160MHZ:
offset = 14;
case CONF_OPER_CHWIDTH_160MHZ:
center = acs_get_bw_center_chan(iface->freq, ACS_BW160);
break;
case CONF_OPER_CHWIDTH_320MHZ:
switch (hostapd_get_bw320_offset(iface->conf)) {
case 1:
center = acs_get_bw_center_chan(iface->freq,
ACS_BW320_1);
break;
case 2:
center = acs_get_bw_center_chan(iface->freq,
ACS_BW320_2);
break;
default:
wpa_printf(MSG_INFO,
"ACS: BW320 offset is not selected");
return;
}
break;
default:
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
wpa_printf(MSG_INFO,
"ACS: Only VHT20/40/80/160 is supported now");
"ACS: Only VHT20/40/80/160/320 is supported now");
return;
}
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
iface->conf->channel + offset);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, center);
}
@@ -980,9 +1286,24 @@ static void acs_study(struct hostapd_iface *iface)
iface->conf->channel = ideal_chan->chan;
iface->freq = ideal_chan->freq;
#ifdef CONFIG_IEEE80211BE
iface->conf->punct_bitmap = ideal_chan->punct_bitmap;
#endif /* CONFIG_IEEE80211BE */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
iface->conf->ieee80211be) {
acs_adjust_secondary(iface);
acs_adjust_center_freq(iface);
}
err = hostapd_select_hw_mode(iface);
if (err) {
wpa_printf(MSG_ERROR,
"ACS: Could not (err: %d) select hw_mode for freq=%d channel=%d",
err, iface->freq, iface->conf->channel);
err = -1;
goto fail;
}
err = 0;
fail:
@@ -1007,6 +1328,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
int err;
iface->scan_cb = NULL;
iface->acs_num_retries = 0;
wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
iface->conf->acs_num_scans);
@@ -1019,7 +1341,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
err = acs_request_scan(iface);
if (err) {
if (err && err != -EBUSY) {
wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
goto fail;
}
@@ -1044,7 +1366,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
((chan->flag & HOSTAPD_CHAN_RADAR) &&
iface->conf->acs_exclude_dfs))
continue;
if (!is_in_chanlist(iface, chan))
@@ -1056,6 +1380,10 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
iface->conf->country[2] == 0x4f)
continue;
*freq++ = chan->freq;
}
@@ -1066,7 +1394,7 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
int i, *freq;
int i, *freq, ret;
int num_channels;
struct hostapd_hw_modes *mode;
@@ -1099,32 +1427,78 @@ static int acs_request_scan(struct hostapd_iface *iface)
return -1;
}
iface->scan_cb = acs_scan_complete;
if (!iface->acs_num_retries)
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans);
else
wpa_printf(MSG_DEBUG,
"ACS: Re-try scanning attempt %d (%d / %d)",
iface->acs_num_retries,
iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans);
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans);
ret = hostapd_driver_scan(iface->bss[0], &params);
os_free(params.freqs);
if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
if (ret == -EBUSY) {
iface->acs_num_retries++;
if (iface->acs_num_retries >= ACS_SCAN_RETRY_MAX_COUNT) {
wpa_printf(MSG_ERROR,
"ACS: Failed to request initial scan (all re-attempts failed)");
acs_fail(iface);
return -1;
}
wpa_printf(MSG_INFO,
"Failed to request acs scan ret=%d (%s) - try to scan after %d seconds",
ret, strerror(-ret), ACS_SCAN_RETRY_INTERVAL);
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
eloop_register_timeout(ACS_SCAN_RETRY_INTERVAL, 0,
acs_scan_retry, iface, NULL);
return 0;
}
if (ret < 0) {
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
acs_cleanup(iface);
os_free(params.freqs);
return -1;
}
os_free(params.freqs);
iface->scan_cb = acs_scan_complete;
return 0;
}
static void acs_scan_retry(void *eloop_data, void *user_data)
{
struct hostapd_iface *iface = eloop_data;
if (acs_request_scan(iface)) {
wpa_printf(MSG_ERROR,
"ACS: Failed to request re-try of initial scan");
acs_fail(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");
if (hostapd_drv_do_acs(iface->bss[0]))
err = hostapd_drv_do_acs(iface->bss[0]);
if (err) {
if (err == 1)
return HOSTAPD_CHAN_INVALID_NO_IR;
return HOSTAPD_CHAN_INVALID;
}
return HOSTAPD_CHAN_ACS;
}
+3
View File
@@ -15,6 +15,9 @@
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
void acs_cleanup(struct hostapd_iface *iface);
#define ACS_SCAN_RETRY_MAX_COUNT 15
#define ACS_SCAN_RETRY_INTERVAL 5
#else /* CONFIG_ACS */
static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
+1 -1
View File
@@ -232,7 +232,7 @@ static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
struct airtime_sta_weight *wt;
wt = hapd->conf->airtime_weight_list;
while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
while (wt && !ether_addr_equal(wt->addr, sta))
wt = wt->next;
return wt ? wt->weight : hapd->conf->airtime_weight;
+173 -32
View File
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
* Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -90,7 +90,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->radius_server_auth_port = 1812;
bss->eap_sim_db_timeout = 1;
bss->eap_sim_id = 3;
bss->eap_sim_aka_fast_reauth_limit = 1000;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->bss_max_idle = 1;
bss->eapol_version = EAPOL_VERSION;
bss->max_listen_interval = 65535;
@@ -120,9 +122,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#endif /* CONFIG_IEEE80211R_AP */
bss->radius_das_time_window = 300;
bss->radius_require_message_authenticator = 1;
bss->anti_clogging_threshold = 5;
bss->sae_sync = 5;
bss->sae_sync = 3;
bss->gas_frag_limit = 1400;
@@ -162,13 +165,17 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
bss->multi_ap_profile = MULTI_AP_PROFILE_2;
#ifdef CONFIG_TESTING_OPTIONS
bss->sae_commit_status = -1;
bss->test_assoc_comeback_type = -1;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_PASN
/* comeback after 10 TUs */
bss->pasn_comeback_after = 10;
bss->pasn_noauth = 1;
#endif /* CONFIG_PASN */
}
@@ -279,6 +286,10 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_6ghz_max_ampdu_len_exp = 7;
conf->he_6ghz_rx_ant_pat = 1;
conf->he_6ghz_tx_ant_pat = 1;
conf->he_6ghz_reg_pwr_type = HE_REG_INFO_6GHZ_AP_TYPE_VLP;
conf->reg_def_cli_eirp_psd = -1;
conf->reg_sub_cli_eirp_psd = -1;
conf->reg_def_cli_eirp = -1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -293,6 +304,8 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
#endif /* CONFIG_AIRTIME_POLICY */
hostapd_set_and_check_bw320_offset(conf, 0);
return conf;
}
@@ -461,9 +474,12 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
(u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase));
pbkdf2_sha1(ssid->wpa_passphrase,
ssid->ssid, ssid->ssid_len,
4096, ssid->wpa_psk->psk, PMK_LEN);
if (pbkdf2_sha1(ssid->wpa_passphrase,
ssid->ssid, ssid->ssid_len,
4096, ssid->wpa_psk->psk, PMK_LEN) != 0) {
wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
ssid->wpa_psk->psk, PMK_LEN);
return 0;
@@ -476,9 +492,11 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK &&
!hostapd_sae_pw_id_in_use(conf) &&
!wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt) &&
!hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
@@ -541,6 +559,10 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
for (i = 0; i < num_servers; i++) {
os_free(servers[i].shared_secret);
os_free(servers[i].ca_cert);
os_free(servers[i].client_cert);
os_free(servers[i].private_key);
os_free(servers[i].private_key_passwd);
}
os_free(servers);
}
@@ -686,6 +708,33 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
}
#ifdef CONFIG_IEEE80211R_AP
void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf)
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
struct ft_remote_r1kh *r1kh, *r1kh_prev;
r0kh = conf->r0kh_list;
conf->r0kh_list = NULL;
while (r0kh) {
r0kh_prev = r0kh;
r0kh = r0kh->next;
os_free(r0kh_prev);
}
r1kh = conf->r1kh_list;
conf->r1kh_list = NULL;
while (r1kh) {
r1kh_prev = r1kh;
r1kh = r1kh->next;
os_free(r1kh_prev);
}
}
#endif /* CONFIG_IEEE80211R_AP */
static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
{
struct anqp_element *elem;
@@ -792,6 +841,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->config_id);
os_free(conf->ca_cert);
os_free(conf->server_cert);
os_free(conf->server_cert2);
@@ -809,6 +859,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->imsi_privacy_key);
os_free(conf->radius_server_clients);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
@@ -816,26 +867,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->time_zone);
#ifdef CONFIG_IEEE80211R_AP
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
struct ft_remote_r1kh *r1kh, *r1kh_prev;
r0kh = conf->r0kh_list;
conf->r0kh_list = NULL;
while (r0kh) {
r0kh_prev = r0kh;
r0kh = r0kh->next;
os_free(r0kh_prev);
}
r1kh = conf->r1kh_list;
conf->r1kh_list = NULL;
while (r1kh) {
r1kh_prev = r1kh;
r1kh = r1kh->next;
os_free(r1kh_prev);
}
}
hostapd_config_clear_rxkhs(conf);
os_free(conf->rxkh_file);
conf->rxkh_file = NULL;
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_WPS
@@ -933,6 +967,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
wpabuf_free(conf->rsnxe_override_ft);
wpabuf_free(conf->gtk_rsc_override);
wpabuf_free(conf->igtk_rsc_override);
wpabuf_free(conf->eapol_m1_elements);
wpabuf_free(conf->eapol_m3_elements);
wpabuf_free(conf->presp_elements);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@@ -943,6 +980,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_DPP
os_free(conf->dpp_name);
os_free(conf->dpp_mud_url);
os_free(conf->dpp_extra_conf_req_name);
os_free(conf->dpp_extra_conf_req_value);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
@@ -1118,10 +1157,9 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
if (next_ok &&
(psk->group ||
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
(addr && ether_addr_equal(psk->addr, addr)) ||
(!addr && p2p_dev_addr &&
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
0))) {
ether_addr_equal(psk->p2p_dev_addr, p2p_dev_addr)))) {
if (vlan_id)
*vlan_id = psk->vlan_id;
return psk->psk;
@@ -1202,6 +1240,14 @@ static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
return false;
}
#ifdef CONFIG_SAE
if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) &&
bss->sae_pwe == SAE_PWE_HUNT_AND_PECK) {
wpa_printf(MSG_INFO, "SAE: Enabling SAE H2E on 6 GHz");
bss->sae_pwe = SAE_PWE_BOTH;
}
#endif /* CONFIG_SAE */
return true;
}
@@ -1243,15 +1289,18 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
"RADIUS checking (macaddr_acl=2) enabled.");
return -1;
}
if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
if (full_config && bss->wpa &&
wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) &&
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
bss->ssid.wpa_psk_file == NULL &&
bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
(bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
@@ -1424,7 +1473,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_FILS
if (full_config && bss->fils_discovery_min_int &&
if (full_config && bss->fils_discovery_max_int &&
(!conf->ieee80211ax || bss->disable_11ax)) {
wpa_printf(MSG_ERROR,
"Currently IEEE 802.11ax support is mandatory to enable FILS discovery transmission.");
return -1;
}
if (full_config && bss->fils_discovery_max_int &&
bss->unsol_bcast_probe_resp_interval) {
wpa_printf(MSG_ERROR,
"Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
@@ -1432,6 +1488,20 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211BE
if (full_config && !bss->disable_11be && bss->disable_11ax) {
bss->disable_11be = true;
wpa_printf(MSG_INFO,
"Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS");
}
#endif /* CONFIG_IEEE80211BE */
if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) {
wpa_printf(MSG_ERROR,
"Hidden SSID is not suppored when MBSSID is enabled");
return -1;
}
return 0;
}
@@ -1463,6 +1533,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
{
size_t i;
if (full_config && is_6ghz_op_class(conf->op_class) &&
!conf->hw_mode_set) {
/* Use the appropriate hw_mode value automatically when the
* op_class parameter has been set, but hw_mode was not. */
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
}
if (full_config && conf->ieee80211d &&
(!conf->country[0] || !conf->country[1])) {
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
@@ -1500,6 +1577,24 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
return -1;
}
#ifdef CONFIG_IEEE80211BE
if (full_config && conf->ieee80211be && !conf->ieee80211ax) {
wpa_printf(MSG_ERROR,
"Cannot set ieee80211be without ieee80211ax");
return -1;
}
if (full_config)
hostapd_set_and_check_bw320_offset(conf,
conf->eht_bw320_offset);
#endif /* CONFIG_IEEE80211BE */
if (full_config && conf->mbssid && !conf->ieee80211ax) {
wpa_printf(MSG_ERROR,
"Cannot enable multiple BSSID support without ieee80211ax");
return -1;
}
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
@@ -1646,3 +1741,49 @@ bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
return with_pk;
}
#endif /* CONFIG_SAE_PK */
int hostapd_acl_comp(const void *a, const void *b)
{
const struct mac_acl_entry *aa = a;
const struct mac_acl_entry *bb = b;
return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
}
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
int vlan_id, const u8 *addr)
{
struct mac_acl_entry *newacl;
newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
if (!newacl) {
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
return -1;
}
*acl = newacl;
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
(*acl)[*num].vlan_id.untagged = vlan_id;
(*acl)[*num].vlan_id.notempty = !!vlan_id;
(*num)++;
return 0;
}
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
const u8 *addr)
{
int i = 0;
while (i < *num) {
if (ether_addr_equal((*acl)[i].addr, addr)) {
os_remove_in_array(*acl, *num, sizeof(**acl), i);
(*num)--;
} else {
i++;
}
}
}
+214 -12
View File
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,12 @@
#include "fst/fst.h"
#include "vlan.h"
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
};
/**
* mesh_conf - local MBSS state and settings
*/
@@ -278,6 +284,7 @@ struct hostapd_bss_config {
char bridge[IFNAMSIZ + 1];
char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
int bridge_hairpin; /* hairpin_mode on bridge members */
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -302,6 +309,7 @@ struct hostapd_bss_config {
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
int radius_require_message_authenticator;
int acct_interim_interval;
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
@@ -331,12 +339,11 @@ struct hostapd_bss_config {
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
#ifdef CONFIG_TESTING_OPTIONS
bool eap_skip_prot_success;
#endif /* CONFIG_TESTING_OPTIONS */
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
} macaddr_acl;
enum macaddr_acl macaddr_acl;
struct mac_acl_entry *accept_mac;
int num_accept_mac;
struct mac_acl_entry *deny_mac;
@@ -364,7 +371,8 @@ struct hostapd_bss_config {
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
PSK_RADIUS_REQUIRED = 2
PSK_RADIUS_REQUIRED = 2,
PSK_RADIUS_DURING_4WAY_HS = 3,
} wpa_psk_radius;
int wpa_pairwise;
int group_cipher; /* wpa_group value override from configuation */
@@ -398,6 +406,7 @@ struct hostapd_bss_config {
int ft_over_ds;
int ft_psk_generate_local;
int r1_max_key_lifetime;
char *rxkh_file;
#endif /* CONFIG_IEEE80211R_AP */
char *ctrl_interface; /* directory for UNIX domain sockets */
@@ -437,8 +446,11 @@ struct hostapd_bss_config {
int eap_teap_pac_no_inner;
int eap_teap_separate_result;
int eap_teap_id;
int eap_teap_method_sequence;
int eap_sim_aka_result_ind;
int eap_sim_id;
char *imsi_privacy_key;
int eap_sim_aka_fast_reauth_limit;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -454,6 +466,9 @@ struct hostapd_bss_config {
*/
int ap_max_inactivity;
int bss_max_idle;
int max_acceptable_idle_period;
bool no_disconnect_on_group_keyerror;
int ignore_broadcast_ssid;
int no_probe_resp_if_max_sta;
@@ -537,6 +552,7 @@ struct hostapd_bss_config {
bool disable_11n;
bool disable_11ac;
bool disable_11ax;
bool disable_11be;
/* IEEE 802.11v */
int time_advertisement;
@@ -662,7 +678,7 @@ struct hostapd_bss_config {
unsigned int sae_sync;
int sae_require_mfp;
int sae_confirm_immediate;
int sae_pwe;
enum sae_pwe sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@@ -693,6 +709,15 @@ struct hostapd_bss_config {
unsigned int oci_freq_override_ft_assoc;
unsigned int oci_freq_override_fils_assoc;
unsigned int oci_freq_override_wnm_sleep;
struct wpabuf *eapol_m1_elements;
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
int test_assoc_comeback_type;
struct wpabuf *presp_elements;
#ifdef CONFIG_IEEE80211BE
u16 eht_oper_puncturing_override;
#endif /* CONFIG_IEEE80211BE */
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -739,6 +764,7 @@ struct hostapd_bss_config {
#endif /* CONFIG_FILS */
int multicast_to_unicast;
int bridge_multicast_to_unicast;
int broadcast_deauth;
@@ -747,12 +773,15 @@ struct hostapd_bss_config {
#ifdef CONFIG_DPP
char *dpp_name;
char *dpp_mud_url;
char *dpp_extra_conf_req_name;
char *dpp_extra_conf_req_value;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
int dpp_relay_port;
int dpp_configurator_connectivity;
int dpp_pfs;
#endif /* CONFIG_DPP2 */
@@ -776,6 +805,14 @@ struct hostapd_bss_config {
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
int multi_ap_profile;
/* Multi-AP Profile-1 clients not allowed to connect */
#define PROFILE1_CLIENT_ASSOC_DISALLOW BIT(0)
/* Multi-AP Profile-2 clients not allowed to connect */
#define PROFILE2_CLIENT_ASSOC_DISALLOW BIT(1)
unsigned int multi_ap_client_disallow;
/* Primary VLAN ID to use in Multi-AP */
int multi_ap_vlanid;
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
@@ -832,6 +869,19 @@ struct hostapd_bss_config {
*/
u32 macsec_replay_window;
/**
* macsec_offload - Enable MACsec offload
*
* This setting applies only when MACsec is in use, i.e.,
* - macsec_policy is enabled
* - the key server has decided to enable MACsec
*
* 0 = MACSEC_OFFLOAD_OFF (default)
* 1 = MACSEC_OFFLOAD_PHY
* 2 = MACSEC_OFFLOAD_MAC
*/
int macsec_offload;
/**
* macsec_port - MACsec port (in SCI)
*
@@ -848,6 +898,13 @@ struct hostapd_bss_config {
*/
int mka_priority;
/**
* macsec_csindex - Cipher suite index for MACsec
*
* Range: 0-1 (default: 0)
*/
int macsec_csindex;
/**
* mka_ckn - MKA pre-shared CKN
*/
@@ -872,6 +929,9 @@ struct hostapd_bss_config {
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_PASN
/* Whether to allow PASN-UNAUTH */
int pasn_noauth;
#ifdef CONFIG_TESTING_OPTIONS
/*
* Normally, KDK should be derived if and only if both sides support
@@ -898,6 +958,29 @@ struct hostapd_bss_config {
u8 ext_capa[EXT_CAPA_MAX_LEN];
u8 rnr;
char *config_id;
bool xrates_supported;
bool ssid_protection;
#ifdef CONFIG_IEEE80211BE
/* The AP is part of an AP MLD */
u8 mld_ap;
/* The MLD ID to which the AP MLD is affiliated with */
u8 mld_id;
/* The AP's MLD MAC address within the AP MLD */
u8 mld_addr[ETH_ALEN];
#ifdef CONFIG_TESTING_OPTIONS
/*
* If set indicate the AP as disabled in the RNR element included in the
* other APs in the AP MLD.
*/
bool mld_indicate_disabled;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
};
/**
@@ -936,6 +1019,15 @@ struct spatial_reuse {
u8 srg_partial_bssid_bitmap[8];
};
/**
* struct eht_phy_capabilities_info - EHT PHY capabilities
*/
struct eht_phy_capabilities_info {
bool su_beamformer;
bool su_beamformee;
bool mu_beamformer;
};
/**
* struct hostapd_config - Per-radio interface configuration
*/
@@ -957,7 +1049,9 @@ struct hostapd_config {
int acs_exclude_dfs;
u8 min_tx_power;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
bool hw_mode_set;
int acs_exclude_6ghz_non_psc;
int enable_background_radar;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -1022,7 +1116,7 @@ struct hostapd_config {
u32 vht_capab;
int ieee80211ac;
int require_vht;
u8 vht_oper_chwidth;
enum oper_chan_width vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
u8 ht40_plus_minus_allowed;
@@ -1045,6 +1139,7 @@ struct hostapd_config {
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
int ecsa_ie_only;
bool delay_eapol_tx;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
@@ -1066,13 +1161,28 @@ struct hostapd_config {
struct he_operation he_op;
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
struct spatial_reuse spr;
u8 he_oper_chwidth;
enum oper_chan_width he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
u8 he_6ghz_max_mpdu;
u8 he_6ghz_max_ampdu_len_exp;
u8 he_6ghz_rx_ant_pat;
u8 he_6ghz_tx_ant_pat;
u8 he_6ghz_reg_pwr_type;
int reg_def_cli_eirp_psd;
int reg_sub_cli_eirp_psd;
/*
* This value should be used when regulatory client EIRP PSD values
* advertised by an AP that is an SP AP or an indoor SP AP are
* insufficient to ensure that regulatory client limits on total EIRP
* are always met for all transmission bandwidths within the bandwidth
* of the APs BSS.
*/
int reg_def_cli_eirp;
bool require_he;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -1100,11 +1210,41 @@ struct hostapd_config {
unsigned int airtime_update_interval;
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
#endif /* CONFIG_AIRTIME_POLICY */
int ieee80211be;
#ifdef CONFIG_IEEE80211BE
enum oper_chan_width eht_oper_chwidth;
u8 eht_oper_centr_freq_seg0_idx;
struct eht_phy_capabilities_info eht_phy_capab;
u16 punct_bitmap; /* a bitmap of disabled 20 MHz channels */
u8 punct_acs_threshold;
u8 eht_default_pe_duration;
u8 eht_bw320_offset;
#endif /* CONFIG_IEEE80211BE */
/* EHT enable/disable config from CHAN_SWITCH */
#define CH_SWITCH_EHT_ENABLED BIT(0)
#define CH_SWITCH_EHT_DISABLED BIT(1)
unsigned int ch_switch_eht_config;
enum mbssid {
MBSSID_DISABLED = 0,
MBSSID_ENABLED = 1,
ENHANCED_MBSSID_ENABLED = 2,
} mbssid;
/* Whether to enable TWT responder in HT and VHT modes */
bool ht_vht_twt_responder;
};
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
static inline enum oper_chan_width
hostapd_get_oper_chwidth(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
return conf->eht_oper_chwidth;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_chwidth;
@@ -1113,8 +1253,15 @@ static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
}
static inline void
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
hostapd_set_oper_chwidth(struct hostapd_config *conf,
enum oper_chan_width oper_chwidth)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_chwidth = oper_chwidth;
if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_chwidth = oper_chwidth;
@@ -1125,6 +1272,10 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
static inline u8
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
return conf->eht_oper_centr_freq_seg0_idx;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_centr_freq_seg0_idx;
@@ -1136,6 +1287,14 @@ static inline void
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
u8 oper_centr_freq_seg0_idx)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
if (is_6ghz_op_class(conf->op_class) &&
center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4)
oper_centr_freq_seg0_idx +=
conf->channel > oper_centr_freq_seg0_idx ? 16 : -16;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
@@ -1164,6 +1323,43 @@ hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
}
static inline u8
hostapd_get_bw320_offset(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) &&
hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_320MHZ)
return conf->eht_bw320_offset;
#endif /* CONFIG_IEEE80211BE */
return 0;
}
static inline void
hostapd_set_and_check_bw320_offset(struct hostapd_config *conf,
u8 bw320_offset)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) &&
op_class_to_ch_width(conf->op_class) == CONF_OPER_CHWIDTH_320MHZ) {
if (conf->channel) {
/* If the channel is set, then calculate bw320_offset
* by center frequency segment 0.
*/
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
conf->eht_bw320_offset = (seg0 - 31) % 64 ? 2 : 1;
} else {
/* If the channel is not set, bw320_offset indicates
* preferred offset of 320 MHz.
*/
conf->eht_bw320_offset = bw320_offset;
}
} else {
conf->eht_bw320_offset = 0;
}
#endif /* CONFIG_IEEE80211BE */
}
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
@@ -1172,6 +1368,7 @@ void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
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_clear_rxkhs(struct hostapd_bss_config *conf);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
@@ -1195,5 +1392,10 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
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 /* HOSTAPD_CONFIG_H */
+306 -53
View File
@@ -75,6 +75,14 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
#ifdef NEED_AP_MLME
pos = buf;
pos = hostapd_eid_rm_enabled_capab(hapd, pos, sizeof(buf));
if (add_buf_data(&assocresp, buf, pos - buf) < 0 ||
add_buf_data(&proberesp, buf, pos - buf) < 0)
goto fail;
#endif /* NEED_AP_MLME */
pos = buf;
pos = hostapd_eid_time_adv(hapd, pos);
if (add_buf_data(&beacon, buf, pos - buf) < 0)
@@ -84,7 +92,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
pos = buf;
pos = hostapd_eid_ext_capab(hapd, pos);
pos = hostapd_eid_ext_capab(hapd, pos, false);
if (add_buf_data(&assocresp, buf, pos - buf) < 0)
goto fail;
pos = hostapd_eid_interworking(hapd, pos);
@@ -200,6 +208,9 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
add_buf(&beacon, hapd->conf->vendor_elements);
add_buf(&proberesp, hapd->conf->vendor_elements);
#ifdef CONFIG_TESTING_OPTIONS
add_buf(&proberesp, hapd->conf->presp_elements);
#endif /* CONFIG_TESTING_OPTIONS */
add_buf(&assocresp, hapd->conf->assocresp_elements);
*beacon_ret = beacon;
@@ -257,9 +268,35 @@ int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
}
bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
struct sta_info *sta)
{
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta) &&
sta->mld_assoc_link_id != hapd->mld_link_id)
return true;
#endif /* CONFIG_IEEE80211BE */
return false;
}
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
/*
* The WPA_STA_AUTHORIZED flag is relevant only for the MLD station and
* not to the link stations (as the authorization is done between the
* MLD peers). Thus, do not propagate the change to the driver for the
* link stations.
*/
if (hostapd_sta_is_link_sta(hapd, sta)) {
wpa_printf(MSG_DEBUG,
"%s: Do not update link station flags (" MACSTR ")",
__func__, MAC2STR(sta->addr));
return 0;
}
if (authorized) {
return hostapd_sta_set_flags(hapd, sta->addr,
hostapd_sta_flags_to_drv(
@@ -277,11 +314,24 @@ int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_flags, total_flags, flags_and, flags_or;
total_flags = hostapd_sta_flags_to_drv(sta->flags);
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
sta->auth_alg == WLAN_AUTH_FT) &&
sta->flags & WLAN_STA_AUTHORIZED)
set_flags |= WPA_STA_AUTHORIZED;
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP |
WPA_STA_AUTHORIZED;
/*
* All the station flags other than WPA_STA_SHORT_PREAMBLE are relevant
* only for the MLD station and not to the link stations (as these flags
* are related to the MLD state and not the link state). As for the
* WPA_STA_SHORT_PREAMBLE, since the station is an EHT station, it must
* support short preamble. Thus, do not propagate the change to the
* driver for the link stations.
*/
if (hostapd_sta_is_link_sta(hapd, sta)) {
wpa_printf(MSG_DEBUG,
"%s: Do not update link station flags (" MACSTR ")",
__func__, MAC2STR(sta->addr));
return 0;
}
flags_or = total_flags & set_flags;
flags_and = total_flags | ~set_flags;
return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
@@ -418,9 +468,11 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
const struct ieee80211_eht_capabilities *eht_capab,
size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
int set, const u8 *link_addr, bool mld_link_sta)
{
struct hostapd_sta_add_params params;
@@ -440,6 +492,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
params.eht_capab = eht_capab;
params.eht_capab_len = eht_capab_len;
params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
@@ -447,6 +501,20 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.qosinfo = qosinfo;
params.support_p2p_ps = supp_p2p_ps;
params.set = set;
params.mld_link_id = -1;
#ifdef CONFIG_IEEE80211BE
/*
* An AP MLD needs to always specify to what link the station needs
* to be added.
*/
if (hapd->conf->mld_ap) {
params.mld_link_id = hapd->mld_link_id;
params.mld_link_addr = link_addr;
params.mld_link_sta = mld_link_sta;
}
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
@@ -507,12 +575,33 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
}
#ifdef CONFIG_IEEE80211BE
int hostapd_if_link_remove(struct hostapd_data *hapd,
enum wpa_driver_if_type type,
const char *ifname, u8 link_id)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_remove)
return -1;
return hapd->driver->link_remove(hapd->drv_priv, type, ifname,
hapd->mld_link_id);
}
#endif /* CONFIG_IEEE80211BE */
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->if_remove == NULL)
return -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap)
return hostapd_if_link_remove(hapd, type, ifname,
hapd->mld_link_id);
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
@@ -527,27 +616,35 @@ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq)
const u8 *addr, int idx, int link_id, u8 *seq)
{
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
return 0;
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
seq);
link_id, seq);
}
int hostapd_flush(struct hostapd_data *hapd)
{
int link_id = -1;
if (hapd->driver == NULL || hapd->driver->flush == NULL)
return 0;
return hapd->driver->flush(hapd->drv_priv);
#ifdef CONFIG_IEEE80211BE
if (hapd->conf && hapd->conf->mld_ap)
link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->flush(hapd->drv_priv, link_id);
}
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
int he_enabled,
int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
@@ -556,18 +653,32 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
edmg_channel, ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
vht_enabled, he_enabled, eht_enabled,
sec_channel_offset, oper_chwidth,
center_segment0, center_segment1,
cmode ? cmode->vht_capab : 0,
cmode ?
&cmode->he_capab[IEEE80211_MODE_AP] : NULL))
&cmode->he_capab[IEEE80211_MODE_AP] : NULL,
cmode ?
&cmode->eht_capab[IEEE80211_MODE_AP] :
NULL, hostapd_get_punct_bitmap(hapd)))
return -1;
if (hapd->driver == NULL)
return 0;
if (hapd->driver->set_freq == NULL)
return 0;
data.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
data.link_id = hapd->mld_link_id;
wpa_printf(MSG_DEBUG,
"hostapd_set_freq: link_id=%d", data.link_id);
}
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
@@ -619,10 +730,19 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country)
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
int link_id = -1;
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
return 0;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap)
link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
cw_min, cw_max, burst_time);
cw_min, cw_max, burst_time,
link_id);
}
@@ -630,8 +750,8 @@ struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags, u8 *dfs_domain)
{
if (hapd->driver == NULL ||
hapd->driver->get_hw_feature_data == NULL)
if (!hapd->driver || !hapd->driver->get_hw_feature_data ||
!hapd->drv_priv)
return NULL;
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
flags, dfs_domain);
@@ -670,6 +790,8 @@ int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_scan_results * hostapd_driver_get_scan_results(
struct hostapd_data *hapd)
{
if (hapd->driver && hapd->driver->get_scan_results)
return hapd->driver->get_scan_results(hapd->drv_priv, NULL);
if (hapd->driver && hapd->driver->get_scan_results2)
return hapd->driver->get_scan_results2(hapd->drv_priv);
return NULL;
@@ -709,6 +831,12 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
params.key_len = key_len;
params.vlan_id = vlan_id;
params.key_flag = key_flag;
params.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap && !(key_flag & KEY_FLAG_PAIRWISE))
params.link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->set_key(hapd->drv_priv, &params);
}
@@ -719,29 +847,61 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const u16 *csa_offs, size_t csa_offs_len,
int no_encrypt)
{
int link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap)
link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
csa_offs, csa_offs_len, no_encrypt, 0);
csa_offs, csa_offs_len, no_encrypt, 0,
link_id);
}
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
int link_id = -1;
const u8 *own_addr = hapd->own_addr;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
struct sta_info *sta = ap_get_sta(hapd, addr);
link_id = hapd->mld_link_id;
if (ap_sta_is_mld(hapd, sta))
own_addr = hapd->mld->mld_addr;
}
#endif /* CONFIG_IEEE80211BE */
if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
return hapd->driver->sta_deauth(hapd->drv_priv, own_addr, addr,
reason, link_id);
}
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
const u8 *own_addr = hapd->own_addr;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
struct sta_info *sta = ap_get_sta(hapd, addr);
if (ap_sta_is_mld(hapd, sta))
own_addr = hapd->mld->mld_addr;
}
#endif /* CONFIG_IEEE80211BE */
if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
return hapd->driver->sta_disassoc(hapd->drv_priv, own_addr, addr,
reason);
}
@@ -756,22 +916,22 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
}
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
static int hapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst,
const u8 *data, size_t len, bool addr3_ap)
{
const u8 *own_addr = hapd->own_addr;
const u8 *bssid;
const u8 wildcard_bssid[ETH_ALEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
struct sta_info *sta;
if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
return 0;
bssid = hapd->own_addr;
if (!is_multicast_ether_addr(dst) &&
if (!addr3_ap && !is_multicast_ether_addr(dst) &&
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
struct sta_info *sta;
/*
* Public Action frames to a STA that is not a member of the BSS
* shall use wildcard BSSID value.
@@ -779,7 +939,7 @@ 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) &&
} else if (!addr3_ap && is_broadcast_ether_addr(dst) &&
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
/*
* The only current use case of Public Action frames with
@@ -788,9 +948,27 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
* so have to use the wildcard BSSID value.
*/
bssid = wildcard_bssid;
#ifdef CONFIG_IEEE80211BE
} else if (hapd->conf->mld_ap) {
sta = ap_get_sta(hapd, dst);
if (ap_sta_is_mld(hapd, sta)) {
own_addr = hapd->mld->mld_addr;
bssid = own_addr;
}
#endif /* CONFIG_IEEE80211BE */
}
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
hapd->own_addr, bssid, data, len, 0);
own_addr, bssid, data, len, 0);
}
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false);
}
@@ -799,20 +977,17 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
unsigned int wait, const u8 *dst,
const u8 *data, size_t len)
{
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
return 0;
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
hapd->own_addr, hapd->own_addr, data,
len, 0);
return hapd_drv_send_action(hapd, freq, wait, dst, data, len, true);
}
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int he_enabled,
int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
int center_segment0, int center_segment1,
bool radar_background)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
@@ -830,18 +1005,25 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
vht_enabled, he_enabled, eht_enabled,
sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP])) {
&cmode->he_capab[IEEE80211_MODE_AP],
&cmode->eht_capab[IEEE80211_MODE_AP],
hostapd_get_punct_bitmap(hapd))) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
data.radar_background = radar_background;
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
iface->cac_started = 1;
if (radar_background)
iface->radar_background.cac_started = 1;
else
iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
}
@@ -852,19 +1034,21 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
const u8 *qos_map_set, u8 qos_map_set_len)
{
if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv ||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING))
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
}
static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode,
int acs_ch_list_all,
int **freq_list)
void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode,
int acs_ch_list_all, bool allow_disabled,
int **freq_list)
{
int i;
bool is_no_ir = false;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
@@ -883,15 +1067,22 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
chan->chan)))
continue;
if (is_6ghz_freq(chan->freq) &&
hapd->iface->conf->acs_exclude_6ghz_non_psc &&
!is_6ghz_psc_frequency(chan->freq))
((hapd->iface->conf->acs_exclude_6ghz_non_psc &&
!is_6ghz_psc_frequency(chan->freq)) ||
(!hapd->iface->conf->ieee80211ax &&
!hapd->iface->conf->ieee80211be)))
continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) &&
!(hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR)) &&
!(chan->max_tx_power < hapd->iface->conf->min_tx_power))
int_array_add_unique(freq_list, chan->freq);
else if ((chan->flag & HOSTAPD_CHAN_NO_IR) &&
is_6ghz_freq(chan->freq))
is_no_ir = true;
}
hapd->iface->is_no_ir = is_no_ir;
}
@@ -909,6 +1100,24 @@ void hostapd_get_ext_capa(struct hostapd_iface *iface)
}
void hostapd_get_mld_capa(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
if (!hapd->driver || !hapd->driver->get_mld_capab)
return;
hapd->driver->get_mld_capab(hapd->drv_priv, WPA_IF_AP_BSS,
&iface->mld_eml_capa,
&iface->mld_mld_capa);
}
/**
* hostapd_drv_do_acs - Start automatic channel selection
* @hapd: BSS data for the device initiating ACS
* Returns: 0 on success, -1 on failure, 1 on failure due to NO_IR (AFC)
*/
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
@@ -922,6 +1131,12 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
os_memset(&params, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
params.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap && hapd->iconf->ieee80211be &&
!hapd->conf->disable_11be)
params.link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
/*
* If no chanlist config parameter is provided, include all enabled
@@ -943,7 +1158,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
selected_mode != mode->mode)
continue;
hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
&freq_list);
false, &freq_list);
}
if (!freq_list && hapd->iface->is_no_ir) {
wpa_printf(MSG_ERROR,
"NO_IR: Interface freq_list is empty. Failing do_acs.");
return 1;
}
params.freq_list = freq_list;
@@ -953,22 +1174,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
params.eht_enabled = !!(hapd->iface->conf->ieee80211be);
params.ch_width = 20;
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
if ((hapd->iface->conf->ieee80211ax ||
if ((hapd->iface->conf->ieee80211be ||
hapd->iface->conf->ieee80211ax ||
hapd->iface->conf->ieee80211ac) &&
params.ht40_enabled) {
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
enum oper_chan_width oper_chwidth;
if (oper_chwidth == CHANWIDTH_80MHZ)
oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
params.ch_width = 80;
else if (oper_chwidth == CHANWIDTH_160MHZ ||
oper_chwidth == CHANWIDTH_80P80MHZ)
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
params.ch_width = 160;
else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
params.ch_width = 320;
}
if (hapd->iface->conf->op_class)
@@ -997,3 +1223,30 @@ int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
return 0;
return hapd->driver->dpp_listen(hapd->drv_priv, enable);
}
#ifdef CONFIG_PASN
int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
const u8 *own_addr, const u8 *peer_addr,
u32 cipher, u8 tk_len, const u8 *tk,
u8 ltf_keyseed_len,
const u8 *ltf_keyseed, u32 action)
{
struct secure_ranging_params params;
if (!hapd->driver || !hapd->driver->set_secure_ranging_ctx)
return 0;
os_memset(&params, 0, sizeof(params));
params.own_addr = own_addr;
params.peer_addr = peer_addr;
params.cipher = cipher;
params.tk_len = tk_len;
params.tk = tk;
params.ltf_keyseed_len = ltf_keyseed_len;
params.ltf_keyseed = ltf_keyseed;
params.action = action;
return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, &params);
}
#endif /* CONFIG_PASN */
+73 -11
View File
@@ -26,6 +26,8 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *assocresp);
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
struct sta_info *sta);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
@@ -43,9 +45,11 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
const struct ieee80211_eht_capabilities *eht_capab,
size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int set, const u8 *link_addr, bool mld_link_sta);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@@ -57,15 +61,18 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_if_link_remove(struct hostapd_data *hapd,
enum wpa_driver_if_type type,
const char *ifname, u8 link_id);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
struct wpa_bss_params *params);
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
const u8 *addr, int idx, int link_id, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
int he_enabled, int sec_channel_offset, int oper_chwidth,
int ht_enabled, int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
@@ -128,13 +135,19 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int he_enabled,
int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int center_segment0, int center_segment1,
bool radar_background);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
const u8 *own_addr, const u8 *addr,
u32 cipher, u8 key_len, const u8 *key,
u8 ltf_keyseed_len,
const u8 *ltf_keyseed, u32 action);
#include "drivers/driver.h"
@@ -147,6 +160,12 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
void hostapd_get_ext_capa(struct hostapd_iface *iface);
void hostapd_get_mld_capa(struct hostapd_iface *iface);
void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode,
int acs_ch_list_all, bool allow_disabled,
int **freq_list);
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
@@ -159,12 +178,13 @@ static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
static inline int hostapd_drv_set_sta_vlan(const char *ifname,
struct hostapd_data *hapd,
const u8 *addr, int vlan_id)
const u8 *addr, int vlan_id,
int link_id)
{
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
return 0;
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
vlan_id);
vlan_id, link_id);
}
static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
@@ -186,13 +206,13 @@ static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
u32 flags)
u32 flags, int link_id)
{
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
return 0;
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
data_len, encrypt,
hapd->own_addr, flags);
hapd->own_addr, flags, link_id);
}
static inline int hostapd_drv_read_sta_data(
@@ -299,6 +319,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
return hapd->driver->switch_channel(hapd->drv_priv, settings);
}
#ifdef CONFIG_IEEE80211AX
static inline int hostapd_drv_switch_color(struct hostapd_data *hapd,
struct cca_settings *settings)
{
if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv)
return -1;
return hapd->driver->switch_color(hapd->drv_priv, settings);
}
#endif /* CONFIG_IEEE80211AX */
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
@@ -362,9 +393,15 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
{
int link_id = -1;
if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
return 0;
return hapd->driver->stop_ap(hapd->drv_priv);
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap)
link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
return hapd->driver->stop_ap(hapd->drv_priv, link_id);
}
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
@@ -416,4 +453,29 @@ hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
}
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211BE
static inline int hostapd_drv_link_add(struct hostapd_data *hapd,
u8 link_id, const u8 *addr)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_add)
return -1;
return hapd->driver->link_add(hapd->drv_priv, link_id, addr, hapd);
}
static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
if (!hapd->conf->mld_ap || !hapd->driver || !hapd->drv_priv ||
!hapd->driver->link_sta_remove)
return -1;
return hapd->driver->link_sta_remove(hapd->drv_priv, hapd->mld_link_id,
addr);
}
#endif /* CONFIG_IEEE80211BE */
#endif /* AP_DRV_OPS */
+3 -3
View File
@@ -55,7 +55,7 @@ static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
struct ap_info *s;
s = iface->ap_hash[STA_HASH(ap)];
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
while (s != NULL && !ether_addr_equal(s->addr, ap))
s = s->hnext;
return s;
}
@@ -100,13 +100,13 @@ static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
s = iface->ap_hash[STA_HASH(ap->addr)];
if (s == NULL) return;
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
if (ether_addr_equal(s->addr, ap->addr)) {
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
return;
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
!ether_addr_equal(s->hnext->addr, ap->addr))
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
+2 -2
View File
@@ -29,9 +29,9 @@ static const char * mlme_auth_alg_str(int alg)
return "SHARED_KEY";
case WLAN_AUTH_FT:
return "FT";
default:
return "unknown";
}
return "unknown";
}
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+94
View File
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
@@ -105,6 +106,22 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
{
struct radius_server_conf srv;
struct hostapd_bss_config *conf = hapd->conf;
#ifdef CONFIG_IEEE80211BE
if (!hostapd_mld_is_first_bss(hapd)) {
struct hostapd_data *first;
wpa_printf(MSG_DEBUG,
"MLD: Using RADIUS server of the first BSS");
first = hostapd_mld_get_first_bss(hapd);
if (!first)
return -1;
hapd->radius_srv = first->radius_srv;
return 0;
}
#endif /* CONFIG_IEEE80211BE */
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
@@ -168,6 +185,9 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev,
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
data->alert.description);
break;
case TLS_UNSAFE_RENEGOTIATION_DISABLED:
/* Not applicable to TLS server */
break;
}
}
#endif /* EAP_TLS_FUNCS */
@@ -207,8 +227,12 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_teap_method_sequence = hapd->conf->eap_teap_method_sequence;
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
cfg->eap_sim_id = hapd->conf->eap_sim_id;
cfg->imsi_privacy_key = hapd->imsi_privacy_key;
cfg->eap_sim_aka_fast_reauth_limit =
hapd->conf->eap_sim_aka_fast_reauth_limit;
cfg->tnc = hapd->conf->tnc;
cfg->wps = hapd->wps;
cfg->fragment_size = hapd->conf->fragment_size;
@@ -222,6 +246,9 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
cfg->server_id_len = 7;
}
cfg->erp = hapd->conf->eap_server_erp;
#ifdef CONFIG_TESTING_OPTIONS
cfg->skip_prot_success = hapd->conf->eap_skip_prot_success;
#endif /* CONFIG_TESTING_OPTIONS */
return cfg;
}
@@ -229,6 +256,35 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
if (!hostapd_mld_is_first_bss(hapd)) {
struct hostapd_data *first;
first = hostapd_mld_get_first_bss(hapd);
if (!first)
return -1;
if (!first->eap_cfg) {
wpa_printf(MSG_DEBUG,
"MLD: First BSS auth_serv does not exist. Init on its behalf");
if (authsrv_init(first))
return -1;
}
wpa_printf(MSG_DEBUG, "MLD: Using auth_serv of the first BSS");
#ifdef EAP_TLS_FUNCS
hapd->ssl_ctx = first->ssl_ctx;
#endif /* EAP_TLS_FUNCS */
hapd->eap_cfg = first->eap_cfg;
#ifdef EAP_SIM_DB
hapd->eap_sim_db_priv = first->eap_sim_db_priv;
#endif /* EAP_SIM_DB */
return 0;
}
#endif /* CONFIG_IEEE80211BE */
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
@@ -292,6 +348,22 @@ int authsrv_init(struct hostapd_data *hapd)
}
#endif /* EAP_TLS_FUNCS */
#ifdef CRYPTO_RSA_OAEP_SHA256
crypto_rsa_key_free(hapd->imsi_privacy_key);
hapd->imsi_privacy_key = NULL;
if (hapd->conf->imsi_privacy_key) {
hapd->imsi_privacy_key = crypto_rsa_key_read(
hapd->conf->imsi_privacy_key, true);
if (!hapd->imsi_privacy_key) {
wpa_printf(MSG_ERROR,
"Failed to read/parse IMSI privacy key %s",
hapd->conf->imsi_privacy_key);
authsrv_deinit(hapd);
return -1;
}
}
#endif /* CRYPTO_RSA_OAEP_SHA256 */
#ifdef EAP_SIM_DB
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
@@ -327,11 +399,33 @@ int authsrv_init(struct hostapd_data *hapd)
void authsrv_deinit(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
if (!hostapd_mld_is_first_bss(hapd)) {
wpa_printf(MSG_DEBUG,
"MLD: Deinit auth_serv of a non-first BSS");
hapd->radius_srv = NULL;
hapd->eap_cfg = NULL;
#ifdef EAP_SIM_DB
hapd->eap_sim_db_priv = NULL;
#endif /* EAP_SIM_DB */
#ifdef EAP_TLS_FUNCS
hapd->ssl_ctx = NULL;
#endif /* EAP_TLS_FUNCS */
return;
}
#endif /* CONFIG_IEEE80211BE */
#ifdef RADIUS_SERVER
radius_server_deinit(hapd->radius_srv);
hapd->radius_srv = NULL;
#endif /* RADIUS_SERVER */
#ifdef CRYPTO_RSA_OAEP_SHA256
crypto_rsa_key_free(hapd->imsi_privacy_key);
hapd->imsi_privacy_key = NULL;
#endif /* CRYPTO_RSA_OAEP_SHA256 */
#ifdef EAP_TLS_FUNCS
if (hapd->ssl_ctx) {
tls_deinit(hapd->ssl_ctx);
+1021 -193
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -15,6 +15,7 @@ struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal);
void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd);
int ieee802_11_set_beacon(struct hostapd_data *hapd);
int ieee802_11_set_beacons(struct hostapd_iface *iface);
int ieee802_11_update_beacons(struct hostapd_iface *iface);
@@ -32,4 +33,7 @@ void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
struct unsol_bcast_probe_resp *ubpr);
#endif /* BEACON_H */
+1 -1
View File
@@ -55,7 +55,7 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
return;
}
ieee802_11_set_beacon(hapd);
ieee802_11_set_beacon_per_bss_only(hapd);
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
return;
+139
View File
@@ -0,0 +1,139 @@
/*
* hostapd / Comeback token mechanism for SAE
* 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.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "hostapd.h"
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "comeback_token.h"
#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
static int comeback_token_hash(const u8 *comeback_key, const u8 *addr, u8 *idx)
{
u8 hash[SHA256_MAC_LEN];
if (hmac_sha256(comeback_key, COMEBACK_KEY_SIZE,
addr, ETH_ALEN, hash) < 0)
return -1;
*idx = hash[0];
return 0;
}
int check_comeback_token(const u8 *comeback_key,
u16 *comeback_pending_idx, const u8 *addr,
const u8 *token, size_t token_len)
{
u8 mac[SHA256_MAC_LEN];
const u8 *addrs[2];
size_t len[2];
u16 token_idx;
u8 idx;
if (token_len != SHA256_MAC_LEN ||
comeback_token_hash(comeback_key, addr, &idx) < 0)
return -1;
token_idx = comeback_pending_idx[idx];
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
wpa_printf(MSG_DEBUG,
"Comeback: Invalid anti-clogging token from "
MACSTR " - token_idx 0x%04x, expected 0x%04x",
MAC2STR(addr), WPA_GET_BE16(token), token_idx);
return -1;
}
addrs[0] = addr;
len[0] = ETH_ALEN;
addrs[1] = token;
len[1] = 2;
if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
2, addrs, len, mac) < 0 ||
os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
return -1;
comeback_pending_idx[idx] = 0; /* invalidate used token */
return 0;
}
struct wpabuf *
auth_build_token_req(struct os_reltime *last_comeback_key_update,
u8 *comeback_key, u16 comeback_idx,
u16 *comeback_pending_idx, size_t idx_len,
int group, const u8 *addr, int h2e)
{
struct wpabuf *buf;
u8 *token;
struct os_reltime now;
u8 idx[2];
const u8 *addrs[2];
size_t len[2];
u8 p_idx;
u16 token_idx;
os_get_reltime(&now);
if (!os_reltime_initialized(last_comeback_key_update) ||
os_reltime_expired(&now, last_comeback_key_update, 60) ||
comeback_idx == 0xffff) {
if (random_get_bytes(comeback_key, COMEBACK_KEY_SIZE) < 0)
return NULL;
wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
comeback_key, COMEBACK_KEY_SIZE);
*last_comeback_key_update = now;
comeback_idx = 0;
os_memset(comeback_pending_idx, 0, idx_len);
}
buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
if (group)
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
if (h2e) {
/* Encapsulate Anti-clogging Token field in a container IE */
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
}
if (comeback_token_hash(comeback_key, addr, &p_idx) < 0) {
wpabuf_free(buf);
return NULL;
}
token_idx = comeback_pending_idx[p_idx];
if (!token_idx) {
comeback_idx++;
token_idx = comeback_idx;
comeback_pending_idx[p_idx] = token_idx;
}
WPA_PUT_BE16(idx, token_idx);
token = wpabuf_put(buf, SHA256_MAC_LEN);
addrs[0] = addr;
len[0] = ETH_ALEN;
addrs[1] = idx;
len[1] = sizeof(idx);
if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
2, addrs, len, token) < 0) {
wpabuf_free(buf);
return NULL;
}
WPA_PUT_BE16(token, token_idx);
return buf;
}
#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
+21
View File
@@ -0,0 +1,21 @@
/*
* hostapd / Comeback token mechanism for SAE
* 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.
*/
#ifndef COMEBACK_TOKEN_H
#define COMEBACK_TOKEN_H
int check_comeback_token(const u8 *comeback_key,
u16 *comeback_pending_idx, const u8 *addr,
const u8 *token, size_t token_len);
struct wpabuf *
auth_build_token_req(struct os_reltime *last_comeback_key_update,
u8 *comeback_key, u16 comeback_idx,
u16 *comeback_pending_idx, size_t idx_len,
int group, const u8 *addr, int h2e);
#endif /* COMEBACK_TOKEN_H */
+586 -13
View File
@@ -24,6 +24,7 @@
#include "ap_drv_ops.h"
#include "mbo_ap.h"
#include "taxonomy.h"
#include "wnm_ap.h"
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
@@ -98,7 +99,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd,
len += ret;
ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
data.current_rx_rate);
data.current_rx_rate / 100);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -130,7 +131,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd,
len += ret;
ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
data.current_tx_rate);
data.current_tx_rate / 100);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -205,9 +206,29 @@ static const char * timeout_next_str(int val)
return "REMOVE";
case STA_DISASSOC_FROM_CLI:
return "DISASSOC_FROM_CLI";
default:
return "?";
}
}
return "?";
static const char * hw_mode_str(enum hostapd_hw_mode mode)
{
switch (mode) {
case HOSTAPD_MODE_IEEE80211B:
return "b";
case HOSTAPD_MODE_IEEE80211G:
return "g";
case HOSTAPD_MODE_IEEE80211A:
return "a";
case HOSTAPD_MODE_IEEE80211AD:
return "ad";
case HOSTAPD_MODE_IEEE80211ANY:
return "any";
case NUM_HOSTAPD_MODES:
return "invalid";
}
return "unknown";
}
@@ -217,6 +238,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
{
int len, res, ret, i;
const char *keyid;
const u8 *dpp_pkhash;
if (!sta)
return 0;
@@ -255,6 +277,14 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
return len;
len += ret;
if (sta->max_idle_period) {
ret = os_snprintf(buf + len, buflen - len,
"max_idle_period=%d\n", sta->max_idle_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
@@ -326,11 +356,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (sta->supp_op_classes &&
buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
if (!os_snprintf_error(buflen - len, res))
len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
sta->supp_op_classes + 1,
sta->supp_op_classes[0]);
len += os_snprintf(buf + len, buflen - len, "\n");
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
if (sta->power_capab) {
@@ -342,6 +376,34 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
len += ret;
}
#ifdef CONFIG_IEEE80211AX
if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
res = os_snprintf(buf + len, buflen - len, "he_capab=");
if (!os_snprintf_error(buflen - len, res))
len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
(const u8 *) sta->he_capab,
sta->he_capab_len);
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211BE
if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
res = os_snprintf(buf + len, buflen - len, "eht_capab=");
if (!os_snprintf_error(buflen - len, res))
len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
(const u8 *) sta->eht_capab,
sta->eht_capab_len);
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AC
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
@@ -350,6 +412,16 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
vht_capabilities_info));
if (!os_snprintf_error(buflen - len, res))
len += res;
res = os_snprintf(buf + len, buflen - len, "vht_capab=");
if (!os_snprintf_error(buflen - len, res))
len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
(const u8 *) sta->vht_capabilities,
sizeof(*sta->vht_capabilities));
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_IEEE80211AC */
@@ -364,11 +436,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
len += os_snprintf(buf + len, buflen - len, "ext_capab=");
res = os_snprintf(buf + len, buflen - len, "ext_capab=");
if (!os_snprintf_error(buflen - len, res))
len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
sta->ext_capability + 1,
sta->ext_capability[0]);
len += os_snprintf(buf + len, buflen - len, "\n");
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
@@ -385,6 +461,33 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
len += ret;
}
dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
if (dpp_pkhash) {
ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
if (!os_snprintf_error(buflen - len, ret))
len += ret;
len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
SHA256_MAC_LEN);
ret = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, ret))
len += ret;
}
#ifdef CONFIG_IEEE80211BE
if (sta->mld_info.mld_sta) {
for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
if (!sta->mld_info.links[i].valid)
continue;
ret = os_snprintf(
buf + len, buflen - len,
"peer_addr[%d]=" MACSTR "\n",
i, MAC2STR(sta->mld_info.links[i].peer_addr));
if (!os_snprintf_error(buflen - len, ret))
len += ret;
}
}
#endif /* CONFIG_IEEE80211BE */
return len;
}
@@ -682,6 +785,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
{
struct hostapd_iface *iface = hapd->iface;
struct hostapd_hw_modes *mode = iface->current_mode;
struct hostapd_config *iconf = hapd->iconf;
int len = 0, ret, j;
size_t i;
@@ -716,6 +820,24 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
return len;
len += ret;
if (mode) {
ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
hw_mode_str(mode->mode));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
if (iconf->country[0] && iconf->country[1]) {
ret = os_snprintf(buf + len, buflen - len,
"country_code=%c%c\ncountry3=0x%X\n",
iconf->country[0], iconf->country[1],
iconf->country[2]);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
if (!iface->cac_started || !iface->dfs_cac_ms) {
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%d\n"
@@ -724,15 +846,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
} else {
/* CAC started and CAC time set - calculate remaining time */
struct os_reltime now;
unsigned int left_time;
long left_time;
os_reltime_age(&iface->dfs_cac_start, &now);
left_time = iface->dfs_cac_ms / 1000 - now.sec;
left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%u\n"
"cac_time_left_seconds=%u\n",
"cac_time_left_seconds=%lu\n",
iface->dfs_cac_ms / 1000,
left_time);
left_time > 0 ? left_time : 0);
}
if (os_snprintf_error(buflen - len, ret))
return len;
@@ -746,6 +868,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"ieee80211ax=%d\n"
"ieee80211be=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@@ -758,12 +881,74 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
!hapd->conf->disable_11ac,
iface->conf->ieee80211ax &&
!hapd->conf->disable_11ax,
iface->conf->ieee80211be &&
!hapd->conf->disable_11be,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
#ifdef CONFIG_IEEE80211BE
if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
ret = os_snprintf(buf + len, buflen - len,
"eht_oper_chwidth=%d\n"
"eht_oper_centr_freq_seg0_idx=%d\n",
iface->conf->eht_oper_chwidth,
iface->conf->eht_oper_centr_freq_seg0_idx);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
if (is_6ghz_op_class(iface->conf->op_class) &&
hostapd_get_oper_chwidth(iface->conf) ==
CONF_OPER_CHWIDTH_320MHZ) {
ret = os_snprintf(buf + len, buflen - len,
"eht_bw320_offset=%d\n",
iface->conf->eht_bw320_offset);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
if (hapd->conf->mld_ap) {
struct hostapd_data *link_bss;
ret = os_snprintf(buf + len, buflen - len,
"num_links=%d\n",
hapd->mld->num_links);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
/* Self BSS */
ret = os_snprintf(buf + len, buflen - len,
"link_id=%d\n"
"link_addr=" MACSTR "\n",
hapd->mld_link_id,
MAC2STR(hapd->own_addr));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
/* Partner BSSs */
for_each_mld_link(link_bss, hapd) {
if (link_bss == hapd)
continue;
ret = os_snprintf(buf + len, buflen - len,
"partner_link[%d]=" MACSTR
"\n",
link_bss->mld_link_id,
MAC2STR(link_bss->own_addr));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
}
}
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
@@ -776,6 +961,16 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
if (!iconf->he_op.he_bss_color_disabled &&
iconf->he_op.he_bss_color) {
ret = os_snprintf(buf + len, buflen - len,
"he_bss_color=%d\n",
iconf->he_op.he_bss_color);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
}
#endif /* CONFIG_IEEE80211AX */
@@ -869,6 +1064,21 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
#ifdef CONFIG_IEEE80211BE
if (bss->conf->mld_ap) {
ret = os_snprintf(buf + len, buflen - len,
"mld_addr[%d]=" MACSTR "\n"
"mld_id[%d]=%d\n"
"mld_link_id[%d]=%d\n",
(int) i, MAC2STR(bss->mld->mld_addr),
(int) i, hostapd_get_mld_id(bss),
(int) i, bss->mld_link_id);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
#endif /* CONFIG_IEEE80211BE */
}
if (hapd->conf->chan_util_avg_period) {
@@ -911,15 +1121,27 @@ int hostapd_parse_csa_settings(const char *pos,
} \
} while (0)
#define SET_CSA_SETTING_EXT(str) \
do { \
const char *pos2 = os_strstr(pos, " " #str "="); \
if (pos2) { \
pos2 += sizeof(" " #str "=") - 1; \
settings->str = atoi(pos2); \
} \
} while (0)
SET_CSA_SETTING(center_freq1);
SET_CSA_SETTING(center_freq2);
SET_CSA_SETTING(bandwidth);
SET_CSA_SETTING(sec_channel_offset);
SET_CSA_SETTING_EXT(punct_bitmap);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
#undef SET_CSA_SETTING_EXT
return 0;
}
@@ -988,7 +1210,7 @@ int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
return -1;
return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
pmkid, expiration, akmp);
pmkid, expiration, akmp, NULL);
}
@@ -1042,8 +1264,359 @@ void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
if (sscanf(pos, "%d", &expiration) != 1)
return NULL;
return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
WPA_KEY_MGMT_SAE, pmkid, expiration);
}
#endif /* CONFIG_MESH */
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
#ifdef CONFIG_WNM_AP
int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
int disassoc_timer;
struct sta_info *sta;
if (hwaddr_aton(cmd, addr))
return -1;
if (cmd[17] != ' ')
return -1;
disassoc_timer = atoi(cmd + 17);
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "Station " MACSTR
" not found for disassociation imminent message",
MAC2STR(addr));
return -1;
}
return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
}
int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
const char *url, *timerstr;
int disassoc_timer;
struct sta_info *sta;
if (hwaddr_aton(cmd, addr))
return -1;
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "Station " MACSTR
" not found for ESS disassociation imminent message",
MAC2STR(addr));
return -1;
}
timerstr = cmd + 17;
if (*timerstr != ' ')
return -1;
timerstr++;
disassoc_timer = atoi(timerstr);
if (disassoc_timer < 0 || disassoc_timer > 65535)
return -1;
url = os_strchr(timerstr, ' ');
if (url == NULL)
return -1;
url++;
return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
}
int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
const char *pos, *end;
int disassoc_timer = 0;
struct sta_info *sta;
u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
u8 bss_term_dur[12];
char *url = NULL;
int ret;
u8 nei_rep[1000];
int nei_len;
u8 mbo[10];
size_t mbo_len = 0;
if (hwaddr_aton(cmd, addr)) {
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
return -1;
}
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "Station " MACSTR
" not found for BSS TM Request message",
MAC2STR(addr));
return -1;
}
pos = os_strstr(cmd, " disassoc_timer=");
if (pos) {
pos += 16;
disassoc_timer = atoi(pos);
if (disassoc_timer < 0 || disassoc_timer > 65535) {
wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
return -1;
}
}
pos = os_strstr(cmd, " valid_int=");
if (pos) {
pos += 11;
valid_int = atoi(pos);
}
pos = os_strstr(cmd, " dialog_token=");
if (pos) {
pos += 14;
dialog_token = atoi(pos);
}
pos = os_strstr(cmd, " bss_term=");
if (pos) {
pos += 10;
req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
/* TODO: TSF configurable/learnable */
bss_term_dur[0] = 4; /* Subelement ID */
bss_term_dur[1] = 10; /* Length */
os_memset(&bss_term_dur[2], 0, 8);
end = os_strchr(pos, ',');
if (end == NULL) {
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
return -1;
}
end++;
WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
}
nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
sizeof(nei_rep));
if (nei_len < 0)
return -1;
pos = os_strstr(cmd, " url=");
if (pos) {
size_t len;
pos += 5;
end = os_strchr(pos, ' ');
if (end)
len = end - pos;
else
len = os_strlen(pos);
url = os_malloc(len + 1);
if (url == NULL)
return -1;
os_memcpy(url, pos, len);
url[len] = '\0';
req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
}
if (os_strstr(cmd, " pref=1"))
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
if (os_strstr(cmd, " abridged=1"))
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
if (os_strstr(cmd, " disassoc_imminent=1"))
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
if (os_strstr(cmd, " link_removal_imminent=1"))
req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT;
#ifdef CONFIG_MBO
pos = os_strstr(cmd, "mbo=");
if (pos) {
unsigned int mbo_reason, cell_pref, reassoc_delay;
u8 *mbo_pos = mbo;
ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
&reassoc_delay, &cell_pref);
if (ret != 3) {
wpa_printf(MSG_DEBUG,
"MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
ret = -1;
goto fail;
}
if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
wpa_printf(MSG_DEBUG,
"Invalid MBO transition reason code %u",
mbo_reason);
ret = -1;
goto fail;
}
/* Valid values for Cellular preference are: 0, 1, 255 */
if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
wpa_printf(MSG_DEBUG,
"Invalid MBO cellular capability %u",
cell_pref);
ret = -1;
goto fail;
}
if (reassoc_delay > 65535 ||
(reassoc_delay &&
!(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
wpa_printf(MSG_DEBUG,
"MBO: Assoc retry delay is only valid in disassoc imminent mode");
ret = -1;
goto fail;
}
*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
*mbo_pos++ = 1;
*mbo_pos++ = mbo_reason;
*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
*mbo_pos++ = 1;
*mbo_pos++ = cell_pref;
if (reassoc_delay) {
*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
*mbo_pos++ = 2;
WPA_PUT_LE16(mbo_pos, reassoc_delay);
mbo_pos += 2;
}
mbo_len = mbo_pos - mbo;
}
#endif /* CONFIG_MBO */
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
valid_int, bss_term_dur, dialog_token, url,
nei_len ? nei_rep : NULL, nei_len,
mbo_len ? mbo : NULL, mbo_len);
#ifdef CONFIG_MBO
fail:
#endif /* CONFIG_MBO */
os_free(url);
return ret;
}
#endif /* CONFIG_WNM_AP */
int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct vlan_description vlan_id;
if (!(*num))
return 0;
if (hwaddr_aton(txtaddr, addr))
return -1;
if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
hostapd_remove_acl_mac(acl, num, addr);
return 0;
}
void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
int *num)
{
while (*num)
hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
}
int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
char *buf, size_t buflen)
{
int i = 0, len = 0, ret = 0;
if (!acl)
return 0;
while (i < num) {
ret = os_snprintf(buf + len, buflen - len,
MACSTR " VLAN_ID=%d\n",
MAC2STR(acl[i].addr),
acl[i].vlan_id.untagged);
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
i++;
len += ret;
}
return len;
}
int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
const char *cmd)
{
u8 addr[ETH_ALEN];
struct vlan_description vlan_id;
int ret = 0, vlanid = 0;
const char *pos;
if (hwaddr_aton(cmd, addr))
return -1;
pos = os_strstr(cmd, "VLAN_ID=");
if (pos)
vlanid = atoi(pos + 8);
if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
if (ret != -1 && *acl)
qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
}
return ret < 0 ? -1 : 0;
}
int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
{
struct sta_info *sta;
struct vlan_description vlan_id;
if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
return 0;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac,
sta->addr, &vlan_id) ||
(vlan_id.notempty &&
vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
}
return 0;
}
int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
{
struct sta_info *sta;
struct vlan_description vlan_id;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (hostapd_maclist_found(hapd->conf->deny_mac,
hapd->conf->num_deny_mac, sta->addr,
&vlan_id) &&
(!vlan_id.notempty ||
!vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
}
return 0;
}
+17
View File
@@ -37,4 +37,21 @@ 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);
int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
const char *cmd);
int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
const char *cmd);
int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
const char *cmd);
int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
const char *cmd);
int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr);
void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
int *num);
int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
char *buf, size_t buflen);
int hostapd_disassoc_accept_mac(struct hostapd_data *hapd);
int hostapd_disassoc_deny_mac(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
+452 -156
View File
@@ -14,11 +14,32 @@
#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "beacon.h"
#include "ap_drv_ops.h"
#include "drivers/driver.h"
#include "dfs.h"
enum dfs_channel_type {
DFS_ANY_CHANNEL,
DFS_AVAILABLE, /* non-radar or radar-available */
DFS_NO_CAC_YET, /* radar-not-yet-available */
};
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx,
enum dfs_channel_type *channel_type);
static bool dfs_use_radar_background(struct hostapd_iface *iface)
{
return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) &&
iface->conf->enable_background_radar;
}
static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
{
int n_chans = 1;
@@ -30,15 +51,15 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
case CONF_OPER_CHWIDTH_USE_HT:
break;
case CHANWIDTH_80MHZ:
case CONF_OPER_CHWIDTH_80MHZ:
n_chans = 4;
break;
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
n_chans = 8;
break;
case CHANWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_80P80MHZ:
n_chans = 4;
*seg1 = 4;
break;
@@ -51,15 +72,27 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
}
/* dfs_channel_available: select new channel according to type parameter */
static int dfs_channel_available(struct hostapd_channel_data *chan,
int skip_radar)
enum dfs_channel_type type)
{
if (type == DFS_NO_CAC_YET) {
/* Select only radar channel where CAC has not been
* performed yet
*/
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
(chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
HOSTAPD_CHAN_DFS_USABLE)
return 1;
return 0;
}
/*
* When radar detection happens, CSA is performed. However, there's no
* time for CAC, so radar channels must be skipped when finding a new
* channel for CSA, unless they are available for immediate use.
*/
if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
HOSTAPD_CHAN_DFS_AVAILABLE))
return 0;
@@ -138,7 +171,7 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
int skip_radar)
enum dfs_channel_type type)
{
struct hostapd_channel_data *first_chan, *chan;
int i;
@@ -156,7 +189,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
* If it's not allowed to use the first channel as primary, decline the
* whole channel range. */
if (!chan_pri_allowed(first_chan)) {
wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed");
return 0;
}
@@ -177,7 +210,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
return 0;
}
if (!dfs_channel_available(chan, skip_radar)) {
if (!dfs_channel_available(chan, type)) {
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
first_chan->freq + i * 20);
return 0;
@@ -207,7 +240,7 @@ static int is_in_chanlist(struct hostapd_iface *iface,
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
int idx, int skip_radar)
int idx, enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
@@ -232,7 +265,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
}
/* Skip incompatible chandefs */
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
if (!dfs_chan_range_available(mode, i, n_chans, type)) {
wpa_printf(MSG_DEBUG,
"DFS: range not available for %d (%d)",
chan->freq, chan->chan);
@@ -249,6 +282,10 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
iface->conf->country[2] == 0x4f)
continue;
if (ret_chan && idx == channel_idx) {
wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
chan->freq, chan->chan);
@@ -279,7 +316,7 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
*oper_centr_freq_seg1_idx = 0;
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
case CONF_OPER_CHWIDTH_USE_HT:
if (secondary_channel == 1)
*oper_centr_freq_seg0_idx = chan->chan + 2;
else if (secondary_channel == -1)
@@ -287,13 +324,13 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
else
*oper_centr_freq_seg0_idx = chan->chan;
break;
case CHANWIDTH_80MHZ:
case CONF_OPER_CHWIDTH_80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
break;
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
case CHANWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_80P80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
break;
@@ -326,28 +363,33 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
channel_no -= 4;
/* VHT/HE */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
/* VHT/HE/EHT */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
iface->conf->ieee80211be) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
case CONF_OPER_CHWIDTH_USE_HT:
break;
case CHANWIDTH_80MHZ:
case CONF_OPER_CHWIDTH_80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
break;
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 14;
break;
case CHANWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_80P80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
iface->conf) - 6;
break;
case CONF_OPER_CHWIDTH_320MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 30;
break;
default:
wpa_printf(MSG_INFO,
"DFS only VHT20/40/80/160/80+80 is supported now");
"DFS only EHT20/40/80/160/80+80/320 is supported now");
channel_no = -1;
break;
}
@@ -409,6 +451,8 @@ static int dfs_check_chans_radar(struct hostapd_iface *iface,
mode = iface->current_mode;
for (i = 0; i < n_chans; i++) {
if (start_chan_idx + i >= mode->num_channels)
break;
channel = &mode->channels[start_chan_idx + i];
if (channel->flag & HOSTAPD_CHAN_RADAR)
res++;
@@ -475,7 +519,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx,
int skip_radar)
enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
@@ -499,7 +543,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
num_available_chandefs);
if (num_available_chandefs == 0)
@@ -508,7 +552,9 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d",
chan_idx, num_available_chandefs);
dfs_find_channel(iface, &chan, chan_idx, type);
if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
return NULL;
@@ -523,7 +569,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
*secondary_channel = 0;
/* Get secondary channel for HT80P80 */
if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CONF_OPER_CHWIDTH_80P80MHZ) {
if (num_available_chandefs <= 1) {
wpa_printf(MSG_ERROR,
"only 1 valid chan, can't support 80+80");
@@ -537,7 +584,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
for (i = 0; i < num_available_chandefs - 1; i++) {
/* start from chan_idx + 1, end when chan_idx - 1 */
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
dfs_find_channel(iface, &chan2, chan_idx2, type);
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
/* two channels are not adjacent */
sec_chan_idx_80p80 = chan2->chan;
@@ -568,6 +615,30 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
}
static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
{
struct hostapd_channel_data *channel;
u8 cf1 = 0, cf2 = 0;
int sec = 0;
channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
skip_radar ? DFS_AVAILABLE :
DFS_ANY_CHANNEL);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
return -1;
}
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = sec;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
return 0;
}
static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
{
struct hostapd_hw_modes *mode;
@@ -736,6 +807,8 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
mode = iface->current_mode;
for (i = 0; i < n_chans; i++) {
if (start_chan_idx + i >= mode->num_channels)
break;
channel = &mode->channels[start_chan_idx + i];
if (!(channel->flag & HOSTAPD_CHAN_RADAR))
continue;
@@ -755,7 +828,6 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
*/
int hostapd_handle_dfs(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
@@ -810,28 +882,17 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
res, res ? "yes": "no");
if (res) {
int sec = 0;
u8 cf1 = 0, cf2 = 0;
channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
if (dfs_set_valid_channel(iface, skip_radar) < 0) {
hostapd_set_state(iface, HAPD_IFACE_DFS);
return 0;
}
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = sec;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
/* Finally start CAC */
hostapd_set_state(iface, HAPD_IFACE_DFS);
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
dfs_use_radar_background(iface) ? " (background)" : "");
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
@@ -844,17 +905,41 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
res = hostapd_start_dfs_cac(
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
iface->conf->ieee80211n, iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
iface->conf->ieee80211ax, iface->conf->ieee80211be,
iface->conf->secondary_channel,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
dfs_use_radar_background(iface));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
return -1;
}
if (dfs_use_radar_background(iface)) {
/* Cache background radar parameters. */
iface->radar_background.channel = iface->conf->channel;
iface->radar_background.secondary_channel =
iface->conf->secondary_channel;
iface->radar_background.freq = iface->freq;
iface->radar_background.centr_freq_seg0_idx =
hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
iface->radar_background.centr_freq_seg1_idx =
hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
/*
* Let's select a random channel according to the
* regulations and perform CAC on dedicated radar chain.
*/
res = dfs_set_valid_channel(iface, 1);
if (res < 0)
return res;
iface->radar_background.temp_ch = 1;
return 1;
}
return 0;
}
@@ -876,19 +961,206 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
}
static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
int channel, int freq,
int secondary_channel,
u8 current_vht_oper_chwidth,
u8 oper_centr_freq_seg0_idx,
u8 oper_centr_freq_seg1_idx)
{
struct hostapd_hw_modes *cmode = iface->current_mode;
int ieee80211_mode = IEEE80211_MODE_AP, err;
struct csa_settings csa_settings;
u8 new_vht_oper_chwidth;
unsigned int i;
unsigned int num_err = 0;
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
"freq=%d chan=%d sec_chan=%d", freq, channel,
secondary_channel);
new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
csa_settings.block_tx = 1;
csa_settings.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (iface->bss[0]->conf->mld_ap)
csa_settings.link_id = iface->bss[0]->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_MESH
if (iface->mconf)
ieee80211_mode = IEEE80211_MODE_MESH;
#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
freq, channel,
iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
iface->conf->ieee80211be,
secondary_channel,
new_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
&cmode->he_capab[ieee80211_mode],
&cmode->eht_capab[ieee80211_mode],
hostapd_get_punct_bitmap(iface->bss[0]));
if (err) {
wpa_printf(MSG_ERROR,
"DFS failed to calculate CSA freq params");
hostapd_disable_iface(iface);
return err;
}
for (i = 0; i < iface->num_bss; i++) {
err = hostapd_switch_channel(iface->bss[i], &csa_settings);
if (err)
num_err++;
}
if (num_err == iface->num_bss) {
wpa_printf(MSG_WARNING,
"DFS failed to schedule CSA (%d) - trying fallback",
err);
iface->freq = freq;
iface->conf->channel = channel;
iface->conf->secondary_channel = secondary_channel;
hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
return 0;
}
/* Channel configuration will be updated once CSA completes and
* ch_switch_notify event is received */
wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
return 0;
}
static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface)
{
int sec = 0;
enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
struct hostapd_channel_data *channel;
u8 oper_centr_freq_seg0_idx = 0;
u8 oper_centr_freq_seg1_idx = 0;
/*
* Allow selection of DFS channel in ETSI to comply with
* uniform spreading.
*/
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
channel_type = DFS_ANY_CHANNEL;
channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
channel_type);
if (!channel ||
channel->chan == iface->conf->channel ||
channel->chan == iface->radar_background.channel)
channel = dfs_downgrade_bandwidth(iface, &sec,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&channel_type);
if (!channel ||
hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
channel->freq, channel->chan,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
iface->conf->ieee80211be,
sec, hostapd_get_oper_chwidth(iface->conf),
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx, true)) {
wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
iface->radar_background.channel = -1;
return;
}
iface->radar_background.channel = channel->chan;
iface->radar_background.freq = channel->freq;
iface->radar_background.secondary_channel = sec;
iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
wpa_printf(MSG_DEBUG,
"%s: setting background chain to chan %d (%d MHz)",
__func__, channel->chan, channel->freq);
}
static bool
hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
{
return dfs_use_radar_background(iface) &&
iface->radar_background.channel != -1 &&
iface->radar_background.freq == freq;
}
static int
hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
{
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
iface->conf->channel = iface->radar_background.channel;
iface->freq = iface->radar_background.freq;
iface->conf->secondary_channel =
iface->radar_background.secondary_channel;
hostapd_set_oper_centr_freq_seg0_idx(
iface->conf, iface->radar_background.centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(
iface->conf, iface->radar_background.centr_freq_seg1_idx);
hostapd_dfs_update_background_chain(iface);
return hostapd_dfs_request_channel_switch(
iface, iface->conf->channel, iface->freq,
iface->conf->secondary_channel, current_vht_oper_chwidth,
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
}
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)
{
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
iface->radar_detected);
if (success) {
/* Complete iface/ap configuration */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
/* Complete AP configuration for the first bring up. */
if (iface->state != HAPD_IFACE_ENABLED)
/* Complete AP configuration for the first bring up. If
* a radar was detected in this channel, interface setup
* will be handled in
* 1. hostapd_event_ch_switch() if switching to a
* non-DFS channel
* 2. on next CAC complete event if switching to another
* DFS channel.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
!iface->radar_detected)
hostapd_setup_interface_complete(iface, 0);
else
iface->cac_started = 0;
@@ -896,6 +1168,22 @@ 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);
/*
* Radar event from background chain for the selected
* channel. Perform CSA, move the main chain to the
* selected channel and configure the background chain
* to a new DFS channel.
*/
if (hostapd_dfs_is_background_event(iface, freq)) {
iface->radar_background.cac_started = 0;
if (!iface->radar_background.temp_ch)
return 0;
iface->radar_background.temp_ch = 0;
return hostapd_dfs_start_channel_switch_background(iface);
}
/*
* Just mark the channel available when CAC completion
* event is received in enabled state. CAC result could
@@ -912,8 +1200,12 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
iface->cac_started = 0;
}
}
} else if (hostapd_dfs_is_background_event(iface, freq)) {
iface->radar_background.cac_started = 0;
hostapd_dfs_update_background_chain(iface);
}
iface->radar_detected = false;
return 0;
}
@@ -940,7 +1232,8 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx, int *skip_radar)
u8 *oper_centr_freq_seg1_idx,
enum dfs_channel_type *channel_type)
{
struct hostapd_channel_data *channel;
@@ -948,22 +1241,22 @@ dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
channel = dfs_get_valid_channel(iface, secondary_channel,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
*skip_radar);
*channel_type);
if (channel) {
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
channel->chan);
return channel;
}
if (*skip_radar) {
*skip_radar = 0;
if (*channel_type != DFS_ANY_CHANNEL) {
*channel_type = DFS_ANY_CHANNEL;
} else {
int oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
if (oper_chwidth == CHANWIDTH_USE_HT)
if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
break;
*skip_radar = 1;
*channel_type = DFS_AVAILABLE;
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
@@ -981,7 +1274,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
int secondary_channel;
u8 oper_centr_freq_seg0_idx = 0;
u8 oper_centr_freq_seg1_idx = 0;
int skip_radar = 0;
enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
int err = 1;
/* Radar detected during active CAC */
@@ -989,13 +1282,13 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
channel_type);
if (!channel) {
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&skip_radar);
&channel_type);
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
return err;
@@ -1022,20 +1315,61 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
}
static int
hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
int freq)
{
if (!dfs_use_radar_background(iface))
return -1; /* Background radar chain not supported. */
wpa_printf(MSG_DEBUG,
"%s called (background CAC active: %s, CSA active: %s)",
__func__, iface->radar_background.cac_started ? "yes" : "no",
hostapd_csa_in_progress(iface) ? "yes" : "no");
/* Check if CSA in progress */
if (hostapd_csa_in_progress(iface))
return 0;
if (hostapd_dfs_is_background_event(iface, freq)) {
/*
* Radar pattern is reported on the background chain.
* Just select a new random channel according to the
* regulations for monitoring.
*/
hostapd_dfs_update_background_chain(iface);
return 0;
}
/*
* If background radar detection is supported and the radar channel
* monitored by the background chain is available switch to it without
* waiting for the CAC.
*/
if (iface->radar_background.channel == -1)
return -1; /* Background radar chain not available. */
if (iface->radar_background.cac_started) {
/*
* Background channel not available yet. Perform CAC on the
* main chain.
*/
iface->radar_background.temp_ch = 1;
return -1;
}
return hostapd_dfs_start_channel_switch_background(iface);
}
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
u8 new_vht_oper_chwidth;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
enum dfs_channel_type channel_type = DFS_AVAILABLE;
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -1054,13 +1388,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* uniform spreading.
*/
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
skip_radar = 0;
channel_type = DFS_ANY_CHANNEL;
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
channel_type);
if (!channel) {
/*
@@ -1068,11 +1402,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* there is another channel where we can switch even if it
* requires to perform a CAC first.
*/
skip_radar = 0;
channel_type = DFS_ANY_CHANNEL;
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&skip_radar);
&channel_type);
if (!channel) {
/*
* Toggle interface state to enter DFS state
@@ -1083,7 +1417,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
return 0;
}
if (!skip_radar) {
if (channel_type == DFS_ANY_CHANNEL) {
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
@@ -1098,73 +1432,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
}
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
channel->chan);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
csa_settings.block_tx = 1;
#ifdef CONFIG_MESH
if (iface->mconf)
ieee80211_mode = IEEE80211_MODE_MESH;
#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
channel->freq,
channel->chan,
iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
secondary_channel,
new_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
&cmode->he_capab[ieee80211_mode]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
hostapd_disable_iface(iface);
return err;
}
for (i = 0; i < iface->num_bss; i++) {
err = hostapd_switch_channel(iface->bss[i], &csa_settings);
if (err)
break;
}
if (err) {
wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
err);
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
return 0;
}
/* Channel configuration will be updated once CSA completes and
* ch_switch_notify event is received */
wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
return 0;
return hostapd_dfs_request_channel_switch(iface, channel->chan,
channel->freq,
secondary_channel,
current_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
}
@@ -1172,12 +1445,12 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
int res;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
iface->radar_detected = true;
/* Proceed only if DFS is not offloaded to the driver */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return 0;
@@ -1186,20 +1459,23 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
return 0;
/* mark radar frequency as invalid */
res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
if (!res)
if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
return 0;
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
if (!res)
return 0;
if (!hostapd_dfs_is_background_event(iface, freq)) {
/* Skip if reported radar event not overlapped our channels */
if (!dfs_are_channels_overlapped(iface, freq, chan_width,
cf1, cf2))
return 0;
}
/* radar detected while operating, switch the channel. */
res = hostapd_dfs_start_channel_switch(iface);
if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
/* Radar detected while operating, switch the channel. */
return hostapd_dfs_start_channel_switch(iface);
}
return res;
return 0;
}
@@ -1219,9 +1495,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
/* Handle cases where all channels were initially unavailable */
if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
/* Handle cases where all channels were initially unavailable */
hostapd_handle_dfs(iface);
} else if (dfs_use_radar_background(iface) &&
iface->radar_background.channel == -1) {
/* Reset radar background chain if disabled */
hostapd_dfs_update_background_chain(iface);
}
return 0;
}
@@ -1259,17 +1540,32 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
/* This is called when the driver indicates that an offloaded DFS has
* started CAC. */
hostapd_set_state(iface, HAPD_IFACE_DFS);
if (hostapd_dfs_is_background_event(iface, freq)) {
iface->radar_background.cac_started = 1;
} else {
/* This is called when the driver indicates that an offloaded
* DFS has started CAC. radar_detected might be set for previous
* DFS channel. Clear it for this new CAC process. */
hostapd_set_state(iface, HAPD_IFACE_DFS);
iface->cac_started = 1;
/* Clear radar_detected in case it is for the previous
* frequency. Also remove disabled link's information in RNR
* element from other links. */
iface->radar_detected = false;
if (iface->interfaces && iface->interfaces->count > 1)
ieee802_11_set_beacons(iface);
}
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
"seg1=%d cac_time=%ds%s",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
iface->dfs_cac_ms / 1000,
hostapd_dfs_is_background_event(iface, freq) ?
" (background)" : "");
os_get_reltime(&iface->dfs_cac_start);
return 0;
}
+1355 -62
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -45,5 +45,10 @@ int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_push_button_stop(struct hostapd_data *hapd);
bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd);
int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd);
#endif /* DPP_HOSTAPD_H */
+781 -100
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -530,9 +530,9 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
default:
return 0;
}
return 0;
}
@@ -546,7 +546,7 @@ static int fils_process_hlp_req(struct hostapd_data *hapd,
" 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) {
if (!ether_addr_equal(sta->addr, pos + ETH_ALEN)) {
wpa_printf(MSG_DEBUG,
"FILS: Ignore HLP request with unexpected source address"
MACSTR, MAC2STR(pos + ETH_ALEN));
@@ -567,9 +567,9 @@ static int fils_process_hlp_req(struct hostapd_data *hapd,
case ETH_P_IP:
return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
end - pkt - 2);
default:
return 0;
}
return 0;
}
+7 -3
View File
@@ -29,6 +29,8 @@
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
/**
* struct gas_query_pending - Pending GAS query
*/
@@ -183,7 +185,7 @@ 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 &&
if (ether_addr_equal(q->addr, addr) &&
q->dialog_token == dialog_token)
return q;
}
@@ -221,7 +223,7 @@ void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
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) {
if (!ether_addr_equal(dst, query->addr)) {
wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
return;
}
@@ -545,6 +547,8 @@ int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
if (pos + 2 > data + len)
return 0;
comeback_delay = WPA_GET_LE16(pos);
if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
pos += 2;
/* Advertisement Protocol element */
@@ -614,7 +618,7 @@ static int gas_query_dialog_token_available(struct gas_query_ap *gas,
{
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 &&
if (ether_addr_equal(dst, q->addr) &&
dialog_token == q->dialog_token)
return 0;
}
+6 -5
View File
@@ -1524,7 +1524,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
#ifdef CONFIG_DPP
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
int prot, struct wpabuf *buf)
int prot, struct wpabuf *buf, int freq)
{
struct wpabuf *tx_buf;
@@ -1582,7 +1582,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
return;
if (prot)
convert_to_protected_dual(tx_buf);
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
hostapd_drv_send_action(hapd, freq ? freq : hapd->iface->freq, 0, sa,
wpabuf_head(tx_buf),
wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
@@ -1593,7 +1593,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
const u8 *data, size_t len, int prot,
int std_addr3)
int std_addr3, int freq)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -1688,7 +1688,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
data, len);
if (!msg)
return;
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg,
freq);
return;
}
#endif /* CONFIG_DPP */
@@ -1871,7 +1872,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
std_addr3);
std_addr3, freq);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+1 -1
View File
@@ -90,6 +90,6 @@ void gas_serv_deinit(struct hostapd_data *hapd);
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
int prot, struct wpabuf *buf);
int prot, struct wpabuf *buf, int freq);
#endif /* GAS_SERV_H */
+1293 -112
View File
File diff suppressed because it is too large Load Diff
+163 -6
View File
@@ -14,6 +14,7 @@
#endif /* CONFIG_SQLITE */
#include "common/defs.h"
#include "common/dpp.h"
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
@@ -43,6 +44,7 @@ struct mesh_conf;
#endif /* CONFIG_CTRL_IFACE_UDP */
struct hostapd_iface;
struct hostapd_mld;
struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface);
@@ -75,18 +77,34 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#ifdef CONFIG_DPP3
struct os_reltime dpp_pb_time;
struct os_reltime dpp_pb_announce_time;
struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT];
struct dpp_bootstrap_info *dpp_pb_bi;
u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
u8 dpp_pb_resp_hash[SHA256_MAC_LEN];
struct os_reltime dpp_pb_last_resp;
bool dpp_pb_result_indicated;
char *dpp_pb_cmd;
#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_IEEE80211BE
struct hostapd_mld **mld;
size_t mld_count;
#endif /* CONFIG_IEEE80211BE */
};
enum hostapd_chan_status {
HOSTAPD_CHAN_VALID = 0, /* channel is ready */
HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */
HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */
HOSTAPD_CHAN_INVALID_NO_IR = 3, /* channel invalid due to AFC NO IR */
};
struct hostapd_probereq_cb {
@@ -207,6 +225,7 @@ struct hostapd_data {
void *ssl_ctx;
void *eap_sim_db_priv;
struct crypto_rsa_key *imsi_privacy_key;
struct radius_server_data *radius_srv;
struct dl_list erp_keys; /* struct eap_server_erp_key */
@@ -273,7 +292,8 @@ struct hostapd_data {
void *wps_event_cb_ctx;
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
int authorized, const u8 *p2p_dev_addr);
int authorized, const u8 *p2p_dev_addr,
const u8 *ip);
void *sta_authorized_cb_ctx;
void (*setup_complete_cb)(void *ctx);
@@ -294,6 +314,17 @@ struct hostapd_data {
unsigned int cs_c_off_ecsa_beacon;
unsigned int cs_c_off_ecsa_proberesp;
#ifdef CONFIG_IEEE80211AX
bool cca_in_progress;
u8 cca_count;
u8 cca_color;
unsigned int cca_c_off_beacon;
unsigned int cca_c_off_proberesp;
struct os_reltime first_color_collision;
struct os_reltime last_color_collision;
u64 color_collision_bitmap;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -311,6 +342,7 @@ struct hostapd_data {
#ifdef CONFIG_PROXYARP
struct l2_packet_data *sock_dhcp;
struct l2_packet_data *sock_ndisc;
bool x_snoop_initialized;
#endif /* CONFIG_PROXYARP */
#ifdef CONFIG_MESH
int num_plinks;
@@ -327,11 +359,15 @@ struct hostapd_data {
#endif /* CONFIG_SQLITE */
#ifdef CONFIG_SAE
#define COMEBACK_KEY_SIZE 8
#define COMEBACK_PENDING_IDX_SIZE 256
/** Key used for generating SAE anti-clogging tokens */
u8 comeback_key[8];
u8 comeback_key[COMEBACK_KEY_SIZE];
struct os_reltime last_comeback_key_update;
u16 comeback_idx;
u16 comeback_pending_idx[256];
u16 comeback_pending_idx[COMEBACK_PENDING_IDX_SIZE];
int dot11RSNASAERetransPeriod; /* msec */
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
@@ -369,8 +405,10 @@ struct hostapd_data {
u8 beacon_req_token;
u8 lci_req_token;
u8 range_req_token;
u8 link_measurement_req_token;
unsigned int lci_req_active:1;
unsigned int range_req_active:1;
unsigned int link_mesr_req_active:1;
int dhcp_sock; /* UDP socket used with the DHCP server */
@@ -387,7 +425,9 @@ struct hostapd_data {
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
size_t dpp_pkex_code_len;
char *dpp_pkex_identifier;
enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
struct os_reltime dpp_last_init;
@@ -406,6 +446,7 @@ struct hostapd_data {
int dpp_chirp_round;
int dpp_chirp_scan_done;
int dpp_chirp_listen;
struct os_reltime dpp_relay_last_needs_ctrl;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -429,6 +470,23 @@ struct hostapd_data {
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_IEEE80211BE
u8 eht_mld_bss_param_change;
struct hostapd_mld *mld;
struct dl_list link;
u8 mld_link_id;
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_NAN_USD
struct nan_de *nan_de;
#endif /* CONFIG_NAN_USD */
u64 scan_cookie; /* Scan instance identifier for the ongoing HT40 scan
*/
};
@@ -442,6 +500,29 @@ struct hostapd_sta_info {
#endif /* CONFIG_TAXONOMY */
};
#ifdef CONFIG_IEEE80211BE
/**
* struct hostapd_mld - hostapd per-mld data structure
*/
struct hostapd_mld {
char name[IFNAMSIZ + 1];
u8 mld_addr[ETH_ALEN];
u8 next_link_id;
u8 num_links;
/* Number of hostapd_data (hapd) referencing this. num_links cannot be
* used since num_links can go to 0 even when a BSS is disabled and
* when it is re-enabled, the MLD should exist and hence it cannot be
* freed when num_links is 0.
*/
u8 refcount;
struct hostapd_data *fbss;
struct dl_list links; /* List head of all affiliated links */
};
#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF
#endif /* CONFIG_IEEE80211BE */
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
@@ -459,6 +540,7 @@ struct hostapd_iface {
HAPD_IFACE_ACS,
HAPD_IFACE_HT_SCAN,
HAPD_IFACE_DFS,
HAPD_IFACE_NO_IR,
HAPD_IFACE_ENABLED
} state;
@@ -497,6 +579,7 @@ struct hostapd_iface {
u64 drv_flags;
u64 drv_flags2;
unsigned int drv_rrm_flags;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -508,6 +591,8 @@ struct hostapd_iface {
const u8 *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
u16 mld_eml_capa, mld_mld_capa;
unsigned int drv_max_acl_mac_addrs;
struct hostapd_hw_modes *hw_features;
@@ -520,6 +605,23 @@ struct hostapd_iface {
int *basic_rates;
int freq;
bool radar_detected;
/* Background radar configuration */
struct {
int channel;
int secondary_channel;
int freq;
int centr_freq_seg0_idx;
int centr_freq_seg1_idx;
/* Main chain is on temporary channel during
* CAC detection on radar offchain.
*/
unsigned int temp_ch:1;
/* CAC started on radar offchain */
unsigned int cac_started:1;
} radar_background;
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
@@ -580,6 +682,7 @@ struct hostapd_iface {
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
unsigned int acs_num_retries;
#endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface);
@@ -596,8 +699,18 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
/* Maximum number of interfaces supported for MBSSID advertisement */
unsigned int mbssid_max_interfaces;
/* Maximum profile periodicity for enhanced MBSSID advertisement */
unsigned int ema_max_periodicity;
int (*enable_iface_cb)(struct hostapd_iface *iface);
int (*disable_iface_cb)(struct hostapd_iface *iface);
/* Configured freq of interface is NO_IR */
bool is_no_ir;
bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */
};
/* hostapd.c */
@@ -625,6 +738,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_bss_only(struct hostapd_data *bss);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
void hostapd_free_hapd_data(struct hostapd_data *hapd);
@@ -647,6 +761,9 @@ void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
@@ -654,13 +771,15 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
const u8 *ie, size_t ie_len,
int ssi_signal),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr,
int mld_assoc_link_id);
/* 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);
const u8 *req_ie, size_t req_ielen, const u8 *resp_ie,
size_t resp_ielen, const u8 *link_addr, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
@@ -670,7 +789,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
int finished);
u16 punct_bitmap, int finished);
struct survey_results;
void hostapd_event_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_results);
@@ -692,4 +811,42 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
struct fst_wpa_obj *iface_obj);
#endif /* CONFIG_FST */
int hostapd_set_acl(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id);
int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
struct hostapd_data *hapd2);
u8 hostapd_get_mld_id(struct hostapd_data *hapd);
int hostapd_mld_add_link(struct hostapd_data *hapd);
int hostapd_mld_remove_link(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd);
void free_beacon_data(struct beacon_data *beacon);
int hostapd_fill_cca_settings(struct hostapd_data *hapd,
struct cca_settings *settings);
#ifdef CONFIG_IEEE80211BE
bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
#define for_each_mld_link(partner, self) \
dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link)
#else /* CONFIG_IEEE80211BE */
static inline bool hostapd_mld_is_first_bss(struct hostapd_data *hapd)
{
return true;
}
#define for_each_mld_link(partner, self) \
if (false)
#endif /* CONFIG_IEEE80211BE */
u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);
#endif /* HOSTAPD_H */
+206 -27
View File
@@ -79,6 +79,9 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
u8 dfs_domain;
enum hostapd_hw_mode mode = HOSTAPD_MODE_IEEE80211ANY;
bool is_6ghz = false;
bool orig_mode_valid = false;
if (hostapd_drv_none(hapd))
return -1;
@@ -95,6 +98,18 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
iface->hw_flags = flags;
iface->dfs_domain = dfs_domain;
if (iface->current_mode) {
/*
* Received driver event CHANNEL_LIST_CHANGED when the current
* hw mode is valid. Clear iface->current_mode temporarily as
* the mode instance will be replaced with a new instance and
* the current pointer would be pointing to freed memory.
*/
orig_mode_valid = true;
mode = iface->current_mode->mode;
is_6ghz = iface->current_mode->is_6ghz;
iface->current_mode = NULL;
}
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = modes;
iface->num_hw_features = num_modes;
@@ -104,6 +119,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
int dfs_enabled = hapd->iconf->ieee80211h &&
(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
/* Restore orignal mode if possible */
if (orig_mode_valid && feature->mode == mode &&
feature->num_channels > 0 &&
is_6ghz == is_6ghz_freq(feature->channels[0].freq))
iface->current_mode = feature;
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
@@ -141,6 +162,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
}
if (orig_mode_valid && !iface->current_mode) {
wpa_printf(MSG_ERROR,
"%s: Could not update iface->current_mode",
__func__);
}
return 0;
}
@@ -371,7 +398,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
hostapd_set_oper_chwidth(iface->conf, CONF_OPER_CHWIDTH_USE_HT);
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -479,6 +506,12 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
else
ieee80211n_scan_channels_5g(iface, &params);
params.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (iface->bss[0]->conf->mld_ap)
params.link_id = iface->bss[0]->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
ret = hostapd_driver_scan(iface->bss[0], &params);
iface->num_ht40_scan_tries++;
os_free(params.freqs);
@@ -494,6 +527,7 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
if (ret == 0) {
iface->scan_cb = ieee80211n_check_scan;
iface->bss[0]->scan_cookie = params.scan_cookie;
return;
}
@@ -529,6 +563,11 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
else
ieee80211n_scan_channels_5g(iface, &params);
params.link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (iface->bss[0]->conf->mld_ap)
params.link_id = iface->bss[0]->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
ret = hostapd_driver_scan(iface->bss[0], &params);
os_free(params.freqs);
@@ -550,6 +589,7 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
}
iface->scan_cb = ieee80211n_check_scan;
iface->bss[0]->scan_cookie = params.scan_cookie;
return 1;
}
@@ -794,6 +834,11 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
}
/* Returns:
* 1 = usable
* 0 = not usable
* -1 = not currently usable due to 6 GHz NO-IR
*/
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int frequency, int primary)
{
@@ -817,6 +862,10 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
if (is_6ghz_freq(chan->freq) && (chan->flag & HOSTAPD_CHAN_NO_IR))
return -1;
return 0;
}
@@ -826,6 +875,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
int i, contiguous = 0;
int num_of_enabled = 0;
int max_contiguous = 0;
int err;
struct ieee80211_edmg_config edmg;
struct hostapd_channel_data *pri_chan;
@@ -865,8 +915,9 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
if (num_of_enabled > 4)
return 0;
if (!hostapd_is_usable_chan(iface, freq, 1))
return 0;
err = hostapd_is_usable_chan(iface, freq, 1);
if (err <= 0)
return err;
if (contiguous > max_contiguous)
max_contiguous = contiguous;
@@ -893,10 +944,75 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
}
static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_config *conf = iface->conf;
u16 bw;
u8 start_chan;
if (!conf->punct_bitmap)
return true;
if (!conf->ieee80211be) {
wpa_printf(MSG_ERROR,
"Currently RU puncturing is supported only if ieee80211be is enabled");
return false;
}
if (iface->freq >= 2412 && iface->freq <= 2484) {
wpa_printf(MSG_ERROR,
"RU puncturing not supported in 2.4 GHz");
return false;
}
/*
* In the 6 GHz band, eht_oper_chwidth is ignored. Use operating class
* to determine channel width.
*/
if (conf->op_class == 137) {
bw = 320;
start_chan = conf->eht_oper_centr_freq_seg0_idx - 30;
} else {
switch (conf->eht_oper_chwidth) {
case 0:
wpa_printf(MSG_ERROR,
"RU puncturing is supported only in 80 MHz and 160 MHz");
return false;
case 1:
bw = 80;
start_chan = conf->eht_oper_centr_freq_seg0_idx - 6;
break;
case 2:
bw = 160;
start_chan = conf->eht_oper_centr_freq_seg0_idx - 14;
break;
default:
return false;
}
}
if (!is_punct_bitmap_valid(bw, (conf->channel - start_chan) / 4,
conf->punct_bitmap)) {
wpa_printf(MSG_ERROR, "Invalid puncturing bitmap");
return false;
}
#endif /* CONFIG_IEEE80211BE */
return true;
}
/* Returns:
* 1 = usable
* 0 = not usable
* -1 = not currently usable due to 6 GHz NO-IR
*/
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_freq;
struct hostapd_channel_data *pri_chan;
int err, err2;
if (!iface->current_mode)
return 0;
@@ -908,18 +1024,25 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
wpa_printf(MSG_ERROR, "Primary frequency not present");
return 0;
}
if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
err = hostapd_is_usable_chan(iface, pri_chan->freq, 1);
if (err <= 0) {
wpa_printf(MSG_ERROR, "Primary frequency not allowed");
return 0;
return err;
}
if (!hostapd_is_usable_edmg(iface))
err = hostapd_is_usable_edmg(iface);
if (err <= 0)
return err;
if (!hostapd_is_usable_punct_bitmap(iface))
return 0;
if (!iface->conf->secondary_channel)
return 1;
if (hostapd_is_usable_chan(iface, iface->freq +
iface->conf->secondary_channel * 20, 0)) {
err = hostapd_is_usable_chan(iface, iface->freq +
iface->conf->secondary_channel * 20, 0);
if (err > 0) {
if (iface->conf->secondary_channel == 1 &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
return 1;
@@ -928,35 +1051,51 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
return 1;
}
if (!iface->conf->ht40_plus_minus_allowed)
return 0;
return err;
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_freq = iface->freq + 20;
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_freq = iface->freq - 20;
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
err2 = hostapd_is_usable_chan(iface, secondary_freq, 0);
if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
}
return 0;
return err;
}
static void hostapd_determine_mode(struct hostapd_iface *iface)
static bool skip_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
int chan;
if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan))
return true;
if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
!mode->is_6ghz)
return true;
return false;
}
int hostapd_determine_mode(struct hostapd_iface *iface)
{
int i;
enum hostapd_hw_mode target_mode;
if (iface->current_mode ||
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return;
return 0;
if (iface->freq < 4000)
target_mode = HOSTAPD_MODE_IEEE80211G;
@@ -970,14 +1109,20 @@ static void hostapd_determine_mode(struct hostapd_iface *iface)
mode = &iface->hw_features[i];
if (mode->mode == target_mode) {
if (skip_mode(iface, mode))
continue;
iface->current_mode = mode;
iface->conf->hw_mode = mode->mode;
break;
}
}
if (!iface->current_mode)
wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
if (!iface->current_mode) {
wpa_printf(MSG_ERROR, "ACS/CSA: Cannot decide mode");
return -1;
}
return 0;
}
@@ -985,11 +1130,17 @@ static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
if (iface->freq) {
int err;
hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
return HOSTAPD_CHAN_INVALID;
err = hostapd_is_usable_chans(iface);
if (err <= 0) {
if (!err)
return HOSTAPD_CHAN_INVALID;
return HOSTAPD_CHAN_INVALID_NO_IR;
}
return HOSTAPD_CHAN_VALID;
}
/*
@@ -1000,6 +1151,8 @@ hostapd_check_chans(struct hostapd_iface *iface)
switch (acs_init(iface)) {
case HOSTAPD_CHAN_ACS:
return HOSTAPD_CHAN_ACS;
case HOSTAPD_CHAN_INVALID_NO_IR:
return HOSTAPD_CHAN_INVALID_NO_IR;
case HOSTAPD_CHAN_VALID:
case HOSTAPD_CHAN_INVALID:
default:
@@ -1039,6 +1192,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
iface->is_no_ir = false;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
iface->freq, iface->conf->channel);
@@ -1048,6 +1202,9 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
hostapd_notify_bad_chans(iface);
goto out;
case HOSTAPD_CHAN_INVALID_NO_IR:
iface->is_no_ir = true;
/* fall through */
case HOSTAPD_CHAN_INVALID:
default:
wpa_printf(MSG_ERROR, "ACS picked unusable channels");
@@ -1070,6 +1227,25 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
}
/**
* hostapd_csa_update_hwmode - Update hardware mode
* @iface: Pointer to interface data.
* Returns: 0 on success, < 0 on failure
*
* Update hardware mode when the operating channel changed because of CSA.
*/
int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
{
if (!iface || !iface->conf)
return -1;
iface->current_mode = NULL;
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
return hostapd_determine_mode(iface);
}
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
@@ -1087,23 +1263,22 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
iface->conf->ieee80211ax) &&
iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
iface->conf->channel == 14) {
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
iface->conf->ieee80211ax = 0;
iface->conf->ieee80211be = 0;
}
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
int chan;
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
!hw_mode_get_channel(mode, iface->freq, &chan))
if (skip_mode(iface, mode))
continue;
iface->current_mode = mode;
@@ -1134,9 +1309,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
iface->is_no_ir = false;
return 0;
case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
return 1;
case HOSTAPD_CHAN_INVALID_NO_IR:
iface->is_no_ir = true;
/* fall through */
case HOSTAPD_CHAN_INVALID:
default:
hostapd_notify_bad_chans(iface);
+12
View File
@@ -15,6 +15,7 @@
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
int hostapd_csa_update_hwmode(struct hostapd_iface *iface);
int hostapd_acs_completed(struct hostapd_iface *iface, int err);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
@@ -28,6 +29,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
int hostapd_determine_mode(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -40,6 +42,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
return -1;
}
static inline int hostapd_csa_update_hwmode(struct hostapd_iface *iface)
{
return 0;
}
static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
{
return -1;
@@ -91,6 +98,11 @@ static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
return 0;
}
static inline int hostapd_determine_mode(struct hostapd_iface *iface)
{
return 0;
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
+2299 -1477
View File
File diff suppressed because it is too large Load Diff
+75 -8
View File
@@ -18,6 +18,12 @@ struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
struct radius_sta;
enum ieee80211_op_mode;
enum oper_chan_width;
struct ieee802_11_elems;
struct sae_pk;
struct sae_pt;
struct sae_password_entry;
struct mld_info;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -45,7 +51,8 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd);
void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
bool mbssid_complete);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
@@ -78,13 +85,35 @@ void hostapd_get_he_capab(struct hostapd_data *hapd,
const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_he_cap,
size_t he_capab_len);
void hostapd_get_eht_capab(struct hostapd_data *hapd,
const struct ieee80211_eht_capabilities *src,
struct ieee80211_eht_capabilities *dest,
size_t len);
u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd,
struct mld_info *mld_info,
u8 *eid, bool include_mld_id);
u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info,
u8 *eid);
size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd,
struct mld_info *info,
bool include_mld_id);
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd);
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
size_t len);
u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd,
struct ieee802_11_elems *elems,
struct sta_info *sta);
int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd,
const u8 *basic_mle, size_t basic_mle_len,
u8 *mld_addr);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
@@ -100,10 +129,10 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *he_6ghz_capab);
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd);
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t len, int ack);
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds);
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
@@ -118,7 +147,8 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
u16 value);
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
@@ -170,7 +200,8 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
u8 *owe_buf, size_t owe_buf_len, u16 *status);
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
const u8 *owe_dh, size_t owe_dh_len,
const u8 *link_addr);
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
@@ -194,7 +225,43 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ext_capab_ie, size_t ext_capab_ie_len);
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type,
bool include_mld_params);
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type,
bool include_mld_params);
int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
int res, struct radius_sta *info);
size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
enum ieee80211_op_mode opmode);
u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode);
u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode,
const u8 *he_capab, size_t he_capab_len,
const u8 *eht_capab, size_t eht_capab_len);
size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
u8 *elem_count, const u8 *known_bss,
size_t known_bss_len, size_t *rnr_len);
u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
unsigned int frame_stype, u8 elem_count,
u8 **elem_offset,
const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
u8 *rnr_count, u8 **rnr_offset, size_t rnr_len);
bool hostapd_is_mld_ap(struct hostapd_data *hapd);
const char * sae_get_password(struct hostapd_data *hapd,
struct sta_info *sta, const char *rx_id,
struct sae_password_entry **pw_entry,
struct sae_pt **s_pt, const struct sae_pk **s_pk);
struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd,
struct sta_info *sta,
struct hostapd_data **assoc_hapd);
int hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *ies, size_t ies_len,
bool reassoc, int tx_link_status,
bool offload);
#endif /* IEEE802_11_H */
+131 -31
View File
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,8 @@
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "sta_info.h"
#include "wpa_auth.h"
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
@@ -43,6 +45,11 @@ struct hostapd_acl_query_data {
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
size_t auth_msg_len;
struct hostapd_acl_query_data *next;
bool radius_psk;
int akm;
u8 *anonce;
u8 *eapol;
size_t eapol_len;
};
@@ -77,7 +84,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
os_get_reltime(&now);
for (entry = hapd->acl_cache; entry; entry = entry->next) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
if (!ether_addr_equal(entry->addr, addr))
continue;
if (os_reltime_expired(&now, &entry->timestamp,
@@ -95,9 +102,11 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
{
if (query == NULL)
if (!query)
return;
os_free(query->auth_msg);
os_free(query->anonce);
os_free(query->eapol);
os_free(query);
}
@@ -111,7 +120,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
query->radius_id = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
if (msg == NULL)
if (!msg)
return -1;
if (radius_msg_make_authenticator(msg) < 0) {
@@ -119,6 +128,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
if (!radius_msg_add_msg_auth(msg))
goto fail;
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
os_strlen(buf))) {
@@ -153,6 +165,31 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
if (query->akm &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
wpa_akm_to_suite(query->akm))) {
wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
goto fail;
}
if (query->anonce &&
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
RADIUS_VENDOR_ID_FREERADIUS,
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
query->anonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
goto fail;
}
if (query->eapol &&
!radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
RADIUS_VENDOR_ID_FREERADIUS,
RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
query->eapol, query->eapol_len)) {
wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
goto fail;
}
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
goto fail;
return 0;
@@ -247,7 +284,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
query = hapd->acl_queries;
while (query) {
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
if (ether_addr_equal(query->addr, addr)) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
return HOSTAPD_ACL_PENDING;
@@ -260,23 +297,23 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
/* No entry in the cache - query external RADIUS server */
query = os_zalloc(sizeof(*query));
if (query == NULL) {
if (!query) {
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
"for ACL query.");
wpa_printf(MSG_DEBUG,
"Failed to send Access-Request for ACL query.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
query->auth_msg = os_memdup(msg, len);
if (query->auth_msg == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"auth frame.");
if (!query->auth_msg) {
wpa_printf(MSG_ERROR,
"Failed to allocate memory for auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
@@ -392,7 +429,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
* Passphrase is NULL iff there is no i-th Tunnel-Password
* attribute in msg.
*/
if (passphrase == NULL)
if (!passphrase)
break;
/*
@@ -464,28 +501,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
prev = query;
query = query->next;
}
if (query == NULL)
if (!query)
return RADIUS_RX_UNKNOWN;
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
"message (id=%d)", query->radius_id);
wpa_printf(MSG_DEBUG,
"Found matching Access-Request for RADIUS message (id=%d)",
query->radius_id);
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
"correct authenticator - dropped\n");
if (radius_msg_verify(
msg, shared_secret, shared_secret_len, req,
hapd->conf->radius_require_message_authenticator)) {
wpa_printf(MSG_INFO,
"Incoming RADIUS packet did not have correct authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
"query", hdr->code);
wpa_printf(MSG_DEBUG,
"Unknown RADIUS message code %d to ACL query",
hdr->code);
return RADIUS_RX_UNKNOWN;
}
/* Insert Accept/Reject info into ACL cache */
cache = os_zalloc(sizeof(*cache));
if (cache == NULL) {
if (!cache) {
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
@@ -506,8 +547,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&info->acct_interim_interval) == 0 &&
info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
wpa_printf(MSG_DEBUG,
"Ignored too small Acct-Interim-Interval %d for STA "
MACSTR,
info->acct_interim_interval,
MAC2STR(query->addr));
info->acct_interim_interval = 0;
@@ -557,20 +599,44 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
if (query->radius_psk) {
struct sta_info *sta;
bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
sta = ap_get_sta(hapd, query->addr);
if (!sta || !sta->wpa_sm) {
wpa_printf(MSG_DEBUG,
"No STA/SM entry found for the RADIUS PSK response");
goto done;
}
#ifdef NEED_AP_MLME
if (success &&
(ieee802_11_set_radius_info(hapd, sta, cache->accepted,
info) < 0 ||
ap_sta_bind_vlan(hapd, sta) < 0))
success = false;
#endif /* NEED_AP_MLME */
wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
} else {
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
info->session_timeout);
hostapd_drv_set_radius_acl_auth(hapd, query->addr,
cache->accepted,
info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
"successful RADIUS ACL query");
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
/* Re-send original authentication frame for 802.11 processing
*/
wpa_printf(MSG_DEBUG,
"Re-sending authentication frame after successful RADIUS ACL query");
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
NULL);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_DRIVER_RADIUS_ACL */
}
done:
if (prev == NULL)
if (!prev)
hapd->acl_queries = query->next;
else
prev->next = query->next;
@@ -646,6 +712,40 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
os_free(prev);
bin_clear_free(prev, sizeof(*prev));
}
}
#ifndef CONFIG_NO_RADIUS
void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
int key_mgmt, const u8 *anonce,
const u8 *eapol, size_t eapol_len)
{
struct hostapd_acl_query_data *query;
query = os_zalloc(sizeof(*query));
if (!query)
return;
query->radius_psk = true;
query->akm = key_mgmt;
os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (anonce)
query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
if (eapol) {
query->eapol = os_memdup(eapol, eapol_len);
query->eapol_len = eapol_len;
}
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG,
"Failed to send Access-Request for RADIUS PSK/ACL query");
hostapd_acl_query_free(query);
return;
}
query->next = hapd->acl_queries;
hapd->acl_queries = query;
}
#endif /* CONFIG_NO_RADIUS */
+4 -1
View File
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,5 +36,8 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src);
void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
int key_mgmt, const u8 *anonce,
const u8 *eapol, size_t eapol_len);
#endif /* IEEE802_11_AUTH_H */
File diff suppressed because it is too large Load Diff
+68 -19
View File
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@@ -29,17 +30,19 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
/* Count the number of 1 bits in RU Index Bitmask */
while (ru) {
if (ru & 0x1)
sz++;
ru >>= 1;
}
/* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */
/* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
sz = (sz * 6) + 7;
if (sz % 8)
sz += 8;
sz /= 8;
/* PPE Pad to count the number of needed full octets */
sz = (sz + 7) / 8;
return sz;
}
@@ -64,6 +67,7 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
{
struct ieee80211_he_capabilities *cap;
size_t cap_len;
u8 ppe_thres_hdr;
cap = (struct ieee80211_he_capabilities *) buf;
cap_len = sizeof(*cap) - sizeof(cap->optional);
@@ -74,9 +78,11 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
if (len < cap_len)
return 1;
cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff;
cap_len += ieee80211_he_ppet_size(ppe_thres_hdr,
cap->he_phy_capab_info);
return len != cap_len;
return len < cap_len;
}
@@ -97,20 +103,22 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
mode->he_capab[opmode].phy_cap);
switch (hapd->iface->conf->he_oper_chwidth) {
case CHANWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_80P80MHZ:
he_oper_chwidth |=
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
case CHANWIDTH_80MHZ:
case CHANWIDTH_USE_HT:
case CONF_OPER_CHWIDTH_80MHZ:
case CONF_OPER_CHWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
break;
default:
break;
}
ie_size += mcs_nss_size + ppet_size;
@@ -195,7 +203,8 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (hapd->iface->conf->he_op.he_er_su_disable)
params |= HE_OPERATION_ER_SU_DISABLE;
if (hapd->iface->conf->he_op.he_bss_color_disabled)
if (hapd->iface->conf->he_op.he_bss_color_disabled ||
hapd->cca_in_progress)
params |= HE_OPERATION_BSS_COLOR_DISABLED;
if (hapd->iface->conf->he_op.he_bss_color_partial)
params |= HE_OPERATION_BSS_COLOR_PARTIAL;
@@ -211,8 +220,20 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
pos += 6; /* skip the fixed part */
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
enum oper_chan_width oper_chwidth =
hostapd_get_oper_chwidth(hapd->iconf);
u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
u8 control;
#ifdef CONFIG_IEEE80211BE
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
if (punct_bitmap) {
punct_update_legacy_bw(punct_bitmap,
hapd->iconf->channel,
&oper_chwidth, &seg0, &seg1);
}
#endif /* CONFIG_IEEE80211BE */
if (!seg0)
seg0 = hapd->iconf->channel;
@@ -220,19 +241,30 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
params |= HE_OPERATION_6GHZ_OPER_INFO;
/* 6 GHz Operation Information field
* IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
* IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element,
* Figure 9-788k
*/
*pos++ = hapd->iconf->channel; /* Primary Channel */
/* Control: Channel Width */
/* Control:
* bits 0-1: Channel Width
* bit 2: Duplicate Beacon
* bits 3-5: Regulatory Info
*/
/* Channel Width */
if (seg1)
*pos++ = 3;
control = 3;
else
*pos++ = center_idx_to_bw_6ghz(seg0);
control = center_idx_to_bw_6ghz(seg0);
control |= hapd->iconf->he_6ghz_reg_pwr_type <<
HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
*pos++ = control;
/* Channel Center Freq Seg0/Seg1 */
if (hapd->iconf->he_oper_chwidth == 2) {
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) {
/*
* Seg 0 indicates the channel center frequency index of
* the 160 MHz channel.
@@ -411,10 +443,10 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
* band/stream cases.
*/
switch (hapd->iface->conf->he_oper_chwidth) {
case CHANWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_80P80MHZ:
mcs_count = 3;
break;
case CHANWIDTH_160MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
mcs_count = 2;
break;
default:
@@ -512,7 +544,8 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
u8 *mac_cap;
if (!hapd->iface->current_mode ||
!hapd->iface->current_mode->he_capab[mode].he_supported)
!hapd->iface->current_mode->he_capab[mode].he_supported ||
!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
return 0;
mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
@@ -520,3 +553,19 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
hapd->iface->conf->he_op.he_twt_responder;
}
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid)
{
if (!hapd->cca_in_progress)
return eid;
/* BSS Color Change Announcement element */
*eid++ = WLAN_EID_EXTENSION;
*eid++ = 3;
*eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT;
*eid++ = hapd->cca_count; /* Color Switch Countdown */
*eid++ = hapd->cca_color; /* New BSS Color Information */
return eid;
}
+2 -3
View File
@@ -479,15 +479,14 @@ static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
}
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
{
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
update_sta_ht(hapd, sta);
else
update_sta_no_ht(hapd, sta);
if (hostapd_ht_operation_update(hapd->iface) > 0)
ieee802_11_set_beacons(hapd->iface);
return hostapd_ht_operation_update(hapd->iface);
}
+174 -41
View File
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,19 +17,29 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "wpa_auth.h"
#include "dpp_hostapd.h"
#include "ieee802_11.h"
static u8 * hostapd_eid_timeout_interval(u8 *pos, u8 type, u32 value)
{
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = type;
WPA_PUT_LE32(pos, value);
pos += 4;
return pos;
}
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
u8 *pos = eid;
u32 timeout, tu;
struct os_reltime now, passed;
u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK;
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
os_get_reltime(&now);
os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
@@ -39,10 +49,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
timeout = 0;
if (timeout < hapd->conf->assoc_sa_query_max_timeout)
timeout++; /* add some extra time for local timers */
WPA_PUT_LE32(pos, timeout);
pos += 4;
return pos;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->test_assoc_comeback_type != -1)
type = hapd->conf->test_assoc_comeback_type;
#endif /* CONFIG_TESTING_OPTIONS */
return hostapd_eid_timeout_interval(eid, type, timeout);
}
@@ -50,13 +62,14 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id)
{
#ifdef CONFIG_OCV
struct sta_info *sta;
#endif /* CONFIG_OCV */
#if defined(CONFIG_OCV) || defined(CONFIG_IEEE80211BE)
struct sta_info *sta = ap_get_sta(hapd, addr);
#endif /* CONFIG_OCV || CONFIG_IEEE80211BE */
struct ieee80211_mgmt *mgmt;
u8 *oci_ie = NULL;
u8 oci_ie_len = 0;
u8 *end;
const u8 *own_addr = hapd->own_addr;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
MACSTR, MAC2STR(addr));
@@ -64,7 +77,6 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
#ifdef CONFIG_OCV
sta = ap_get_sta(hapd, addr);
if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
struct wpa_channel_info ci;
@@ -107,11 +119,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
return;
}
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->sa, own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
@@ -140,6 +157,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
u8 *oci_ie = NULL;
u8 oci_ie_len = 0;
u8 *end;
const u8 *own_addr = hapd->own_addr;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
MACSTR, MAC2STR(sa));
@@ -199,11 +217,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
MACSTR, MAC2STR(sa));
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(resp->da, sa, ETH_ALEN);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->sa, own_addr, ETH_ALEN);
os_memcpy(resp->bssid, own_addr, ETH_ALEN);
resp->u.action.category = WLAN_ACTION_SA_QUERY;
resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
@@ -339,7 +362,8 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
}
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx,
bool mbssid_complete)
{
*pos = 0x00;
@@ -363,6 +387,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
if (hapd->conf->bss_transition)
*pos |= 0x08; /* Bit 19 - BSS Transition */
if (hapd->iconf->mbssid)
*pos |= 0x40; /* Bit 22 - Multiple BSSID */
break;
case 3: /* Bits 24-31 */
#ifdef CONFIG_WNM_AP
@@ -412,10 +438,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax &&
hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
if (hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
*pos |= 0x40; /* Bit 78 - TWT responder */
#endif /* CONFIG_IEEE80211AX */
if (hostapd_get_ht_vht_twt_responder(hapd))
*pos |= 0x40; /* Bit 78 - TWT responder */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -435,6 +462,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_BEACON_PROTECTION))
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED)
*pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */
if (mbssid_complete)
*pos |= 0x01; /* Bit 80 - Complete List of NonTxBSSID
* Profiles */
break;
case 11: /* Bits 88-95 */
#ifdef CONFIG_SAE_PK
@@ -448,7 +480,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
}
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid,
bool mbssid_complete)
{
u8 *pos = eid;
u8 len = EXT_CAPA_MAX_LEN, i;
@@ -459,7 +492,7 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
for (i = 0; i < len; i++, pos++) {
hostapd_ext_capab_byte(hapd, pos, i);
hostapd_ext_capab_byte(hapd, pos, i, mbssid_complete);
if (i < hapd->iface->extended_capa_len) {
*pos &= ~hapd->iface->extended_capa_mask[i];
@@ -470,6 +503,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos &= ~hapd->conf->ext_capa_mask[i];
*pos |= hapd->conf->ext_capa[i];
}
/* Clear bits 83 and 22 if EMA and MBSSID are not enabled
* otherwise association fails with some clients */
if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED)
*pos &= ~0x08;
if (i == 2 && !hapd->iconf->mbssid)
*pos &= ~0x40;
}
while (len > 0 && eid[1 + len] == 0) {
@@ -697,12 +737,14 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
}
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
u16 value)
{
u8 *pos = eid;
#ifdef CONFIG_WNM_AP
if (hapd->conf->ap_max_inactivity > 0) {
if (hapd->conf->ap_max_inactivity > 0 &&
hapd->conf->bss_max_idle) {
unsigned int val;
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
*pos++ = 3;
@@ -715,9 +757,13 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
val = 1;
if (val > 65535)
val = 65535;
if (value)
val = value;
WPA_PUT_LE16(pos, val);
pos += 2;
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
/* Set the Protected Keep-Alive Required bit based on
* configuration */
*pos++ = hapd->conf->bss_max_idle == 2 ? BIT(0) : 0x00;
}
#endif /* CONFIG_WNM_AP */
@@ -873,7 +919,7 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
{
#ifdef CONFIG_DPP2
if (hapd->conf->dpp_configurator_connectivity)
if (hostapd_dpp_configurator_connectivity(hapd))
return 6;
#endif /* CONFIG_DPP2 */
return 0;
@@ -885,7 +931,7 @@ u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
u8 *pos = eid;
#ifdef CONFIG_DPP2
if (!hapd->conf->dpp_configurator_connectivity || len < 6)
if (!hostapd_dpp_configurator_connectivity(hapd) || len < 6)
return pos;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
@@ -998,7 +1044,7 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
* If a VHT Operation element was present, use it to determine
* the supported channel bandwidth.
*/
if (oper->vht_op_info_chwidth == 0) {
if (oper->vht_op_info_chwidth == CHANWIDTH_USE_HT) {
requested_bw = ht_40mhz ? 40 : 20;
} else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
requested_bw = 80;
@@ -1051,7 +1097,7 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
bool sae_pk = false;
u16 capab = 0;
u32 capab = 0, tmp;
size_t flen;
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
@@ -1062,9 +1108,11 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
#endif /* CONFIG_SAE_PK */
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
(hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
hapd->conf->sae_pwe != 3) {
(hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
hapd->conf->sae_pwe == SAE_PWE_BOTH ||
hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk ||
wpa_key_mgmt_sae_ext_key(hapd->conf->wpa_key_mgmt)) &&
hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (sae_pk)
@@ -1072,24 +1120,109 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
#endif /* CONFIG_SAE_PK */
}
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
if (hapd->conf->ssid_protection)
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
flen = (capab & 0xff00) ? 2 : 1;
if (len < 2 + flen || !capab)
if (!capab)
return eid; /* no supported extended RSN capabilities */
tmp = capab;
flen = 0;
while (tmp) {
flen++;
tmp >>= 8;
}
if (len < 2 + flen)
return eid; /* no supported extended RSN capabilities */
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
*pos++ = flen;
*pos++ = capab & 0x00ff;
capab >>= 8;
if (capab)
*pos++ = capab;
while (capab) {
*pos++ = capab & 0xff;
capab >>= 8;
}
return pos;
}
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ext_capab_ie, size_t ext_capab_ie_len)
{
/* check for QoS Map support */
if (ext_capab_ie_len >= 5) {
if (ext_capab_ie[4] & 0x01)
sta->qos_map_enabled = 1;
}
if (ext_capab_ie_len > 0) {
sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
os_free(sta->ext_capability);
sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
if (sta->ext_capability) {
sta->ext_capability[0] = ext_capab_ie_len;
os_memcpy(sta->ext_capability + 1, ext_capab_ie,
ext_capab_ie_len);
}
}
return WLAN_STATUS_SUCCESS;
}
struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd,
struct sta_info *sta,
struct hostapd_data **assoc_hapd)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *other_hapd = NULL;
struct sta_info *tmp_sta;
if (!ap_sta_is_mld(hapd, sta))
return NULL;
*assoc_hapd = hapd;
/* The station is the one on which the association was performed */
if (sta->mld_assoc_link_id == hapd->mld_link_id)
return sta;
other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id);
if (!other_hapd) {
wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u",
sta->mld_assoc_link_id);
return sta;
}
/*
* Iterate over the stations and find the one with the matching link ID
* and association ID.
*/
for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) {
if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id &&
tmp_sta->aid == sta->aid) {
*assoc_hapd = other_hapd;
return tmp_sta;
}
}
#endif /* CONFIG_IEEE80211BE */
return sta;
}
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd)
{
return hapd->iconf->ht_vht_twt_responder &&
((hapd->iconf->ieee80211n && !hapd->conf->disable_11n) ||
(hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)) &&
(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER);
}
+23 -9
View File
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
@@ -75,6 +76,13 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
enum oper_chan_width oper_chwidth =
hostapd_get_oper_chwidth(hapd->iconf);
u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx;
u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx;
#ifdef CONFIG_IEEE80211BE
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
#endif /* CONFIG_IEEE80211BE */
if (is_6ghz_op_class(hapd->iconf->op_class))
return eid;
@@ -85,23 +93,29 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
oper = (struct ieee80211_vht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
#ifdef CONFIG_IEEE80211BE
if (punct_bitmap) {
punct_update_legacy_bw(punct_bitmap,
hapd->iconf->channel,
&oper_chwidth, &seg0, &seg1);
}
#endif /* CONFIG_IEEE80211BE */
/*
* center freq = 5 GHz + (5 * index)
* So index 42 gives center freq 5.210 GHz
* which is channel 42 in 5G band
*/
oper->vht_op_info_chan_center_freq_seg0_idx =
hapd->iconf->vht_oper_centr_freq_seg0_idx;
oper->vht_op_info_chan_center_freq_seg1_idx =
hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chan_center_freq_seg0_idx = seg0;
oper->vht_op_info_chan_center_freq_seg1_idx = seg1;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
if (hapd->iconf->vht_oper_chwidth == 2) {
oper->vht_op_info_chwidth = oper_chwidth;
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
/*
* Convert 160 MHz channel width to new style as interop
* workaround.
*/
oper->vht_op_info_chwidth = 1;
oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
oper->vht_op_info_chan_center_freq_seg1_idx =
oper->vht_op_info_chan_center_freq_seg0_idx;
if (hapd->iconf->channel <
@@ -109,12 +123,12 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
else
oper->vht_op_info_chan_center_freq_seg0_idx += 8;
} else if (hapd->iconf->vht_oper_chwidth == 3) {
} else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/*
* Convert 80+80 MHz channel width to new style as interop
* workaround.
*/
oper->vht_op_info_chwidth = 1;
oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
}
/* VHT Basic MCS set comes from hw */
+187 -46
View File
@@ -43,9 +43,9 @@
#ifdef CONFIG_HS20
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation);
int remediation, bool logoff);
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -95,39 +95,46 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
int link_id = -1;
#ifdef CONFIG_IEEE80211BE
link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1;
#endif /* CONFIG_IEEE80211BE */
hostapd_drv_hapd_send_eapol(
hapd, sta->addr, buf, len,
encrypt, hostapd_sta_flags_to_drv(sta->flags));
encrypt, hostapd_sta_flags_to_drv(sta->flags), link_id);
}
os_free(buf);
}
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
static void ieee802_1x_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta,
bool authorized, bool mld)
{
int res;
bool update;
if (sta->flags & WLAN_STA_PREAUTH)
return;
if (authorized) {
ap_sta_set_authorized(hapd, sta, 1);
res = hostapd_set_authorized(hapd, sta, 1);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "authorizing port");
} else {
ap_sta_set_authorized(hapd, sta, 0);
res = hostapd_set_authorized(hapd, sta, 0);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
}
update = ap_sta_set_authorized_flag(hapd, sta, authorized);
res = hostapd_set_authorized(hapd, sta, authorized);
if (update)
ap_sta_set_authorized_event(hapd, sta, authorized);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "%sauthorizing port",
authorized ? "" : "un");
if (res && errno != ENOENT) {
if (!mld && res && errno != ENOENT) {
wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
" flags for kernel driver (errno=%d).",
MAC2STR(sta->addr), errno);
} else if (mld && res) {
wpa_printf(MSG_DEBUG,
"MLD: Could not set station " MACSTR " flags",
MAC2STR(sta->addr));
}
if (authorized) {
@@ -137,6 +144,64 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
static void ieee802_1x_ml_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta,
bool authorized)
{
#ifdef CONFIG_IEEE80211BE
unsigned int i, link_id;
if (!hostapd_is_mld_ap(hapd))
return;
/*
* Authorizing the station should be done only in the station
* performing the association
*/
if (authorized && hapd->mld_link_id != sta->mld_assoc_link_id)
return;
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct mld_link_info *link = &sta->mld_info.links[link_id];
if (!link->valid)
continue;
for (i = 0; i < hapd->iface->interfaces->count; i++) {
struct sta_info *tmp_sta;
struct hostapd_data *tmp_hapd =
hapd->iface->interfaces->iface[i]->bss[0];
if (!hostapd_is_ml_partner(hapd, tmp_hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
tmp_sta = tmp_sta->next) {
if (tmp_sta == sta ||
tmp_sta->mld_assoc_link_id !=
sta->mld_assoc_link_id ||
tmp_sta->aid != sta->aid)
continue;
ieee802_1x_set_authorized(tmp_hapd, tmp_sta,
authorized, true);
break;
}
}
}
#endif /* CONFIG_IEEE80211BE */
}
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
ieee802_1x_set_authorized(hapd, sta, authorized, false);
ieee802_1x_ml_set_sta_authorized(hapd, sta, !!authorized);
}
#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@@ -702,6 +767,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
if (!radius_msg_add_msg_auth(msg))
goto fail;
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
sm->identity, sm->identity_len)) {
@@ -998,7 +1066,7 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
size_t len)
size_t len, enum frame_encryption encrypted)
{
if (sta->pending_eapol_rx) {
wpabuf_free(sta->pending_eapol_rx->buf);
@@ -1016,21 +1084,39 @@ static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
return;
}
sta->pending_eapol_rx->encrypted = encrypted;
os_get_reltime(&sta->pending_eapol_rx->rx_time);
}
static bool ieee802_1x_check_encryption(struct sta_info *sta,
enum frame_encryption encrypted,
u8 type)
{
if (encrypted != FRAME_NOT_ENCRYPTED)
return true;
if (type != IEEE802_1X_TYPE_EAP_PACKET &&
type != IEEE802_1X_TYPE_EAPOL_START &&
type != IEEE802_1X_TYPE_EAPOL_LOGOFF)
return true;
if (!(sta->flags & WLAN_STA_MFP))
return true;
return !wpa_auth_pairwise_set(sta->wpa_sm);
}
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
* @sa: Source address (sender of the EAPOL frame)
* @buf: EAPOL frame
* @len: Length of buf in octets
* @encrypted: Whether the frame was encrypted
*
* This function is called for each incoming EAPOL frame from the interface
*/
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len)
size_t len, enum frame_encryption encrypted)
{
struct sta_info *sta;
struct ieee802_1x_hdr *hdr;
@@ -1043,8 +1129,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
!hapd->conf->wps_state)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
(unsigned long) len, MAC2STR(sa));
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR
" (encrypted=%d)",
(unsigned long) len, MAC2STR(sa), encrypted);
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
@@ -1054,7 +1141,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
" for later use", MAC2STR(sta->addr));
ieee802_1x_save_eapol(sta, buf, len);
ieee802_1x_save_eapol(sta, buf, len, encrypted);
}
return;
@@ -1114,6 +1201,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
}
if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) {
wpa_printf(MSG_DEBUG,
"IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected");
return;
}
if (!sta->eapol_sm) {
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
if (!sta->eapol_sm)
@@ -1684,23 +1777,35 @@ static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
struct sta_info *sta, u8 *pos,
struct sta_info *sta, const u8 *pos,
size_t len)
{
size_t url_len;
unsigned int timeout;
if (len < 3)
return; /* Malformed information */
url_len = len - 3;
sta->hs20_deauth_requested = 1;
sta->hs20_deauth_on_ack = url_len == 0;
wpa_printf(MSG_DEBUG,
"HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
*pos, WPA_GET_LE16(pos + 1));
"HS 2.0: Deauthentication request - Code %u Re-auth Delay %u URL length %zu",
*pos, WPA_GET_LE16(pos + 1), url_len);
wpabuf_free(sta->hs20_deauth_req);
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
if (sta->hs20_deauth_req) {
wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
wpabuf_put_u8(sta->hs20_deauth_req, len - 3);
wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3);
wpabuf_put_u8(sta->hs20_deauth_req, url_len);
wpabuf_put_data(sta->hs20_deauth_req, pos + 3, url_len);
}
ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
timeout = hapd->conf->hs20_deauth_req_timeout;
/* If there is no URL, no need to provide time to fetch it. Use a short
* timeout here to allow maximum time for completing 4-way handshake and
* WNM-Notification delivery. Acknowledgement of the frame will result
* in cutting this wait further. */
if (!url_len && timeout > 2)
timeout = 2;
ap_sta_session_timeout(hapd, sta, timeout);
}
@@ -1788,6 +1893,7 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
buf = NULL;
sta->remediation = 0;
sta->hs20_deauth_requested = 0;
sta->hs20_deauth_on_ack = 0;
for (;;) {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
@@ -1936,16 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
sta = sm->sta;
/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
* present when packet contains an EAP-Message attribute */
if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
0) < 0 &&
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) {
wpa_printf(MSG_INFO,
"Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
@@ -2249,16 +2346,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
}
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
int preauth, int remediation)
static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
int preauth, int remediation, bool logoff)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
if (preauth)
if (preauth) {
rsn_preauth_finished(hapd, sta, success);
else
ieee802_1x_finished(hapd, sta, success, remediation);
return false;
}
return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
}
@@ -2434,6 +2533,30 @@ int ieee802_1x_init(struct hostapd_data *hapd)
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
#ifdef CONFIG_IEEE80211BE
if (!hostapd_mld_is_first_bss(hapd)) {
struct hostapd_data *first;
first = hostapd_mld_get_first_bss(hapd);
if (!first)
return -1;
if (!first->eapol_auth) {
wpa_printf(MSG_DEBUG,
"MLD: First BSS IEEE 802.1X state machine does not exist. Init on its behalf");
if (ieee802_1x_init(first))
return -1;
}
wpa_printf(MSG_DEBUG,
"MLD: Using IEEE 802.1X state machine of the first BSS");
hapd->eapol_auth = first->eapol_auth;
return 0;
}
#endif /* CONFIG_IEEE80211BE */
dl_list_init(&hapd->erp_keys);
os_memset(&conf, 0, sizeof(conf));
@@ -2448,6 +2571,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
#ifdef CONFIG_TESTING_OPTIONS
conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success;
#endif /* CONFIG_TESTING_OPTIONS */
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -2515,6 +2641,16 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
if (!hostapd_mld_is_first_bss(hapd)) {
wpa_printf(MSG_DEBUG,
"MLD: Deinit IEEE 802.1X state machine of a non-first BSS");
hapd->eapol_auth = NULL;
return;
}
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
#endif /* CONFIG_WEP */
@@ -2936,9 +3072,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation)
int remediation, bool logoff)
{
const u8 *key;
size_t len;
@@ -2998,6 +3134,11 @@ 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.
*/
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
logoff ? 0 : 10);
if (logoff && sta->wpa_sm)
return true;
}
return false;
}
+1 -1
View File
@@ -19,7 +19,7 @@ struct radius_msg;
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len);
size_t len, enum frame_encryption encrypted);
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
+267
View File
@@ -0,0 +1,267 @@
/*
* NAN unsynchronized service discovery (USD)
* Copyright (c) 2024, Qualcomm Innovation Center, 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/wpa_ctrl.h"
#include "common/nan_de.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "nan_usd_ap.h"
static int hostapd_nan_de_tx(void *ctx, unsigned int freq,
unsigned int wait_time,
const u8 *dst, const u8 *src, const u8 *bssid,
const struct wpabuf *buf)
{
struct hostapd_data *hapd = ctx;
wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
" A3=" MACSTR " len=%zu",
MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
wpabuf_len(buf));
/* TODO: Force use of OFDM */
return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
wpabuf_head(buf), wpabuf_len(buf));
}
static int hostapd_nan_de_listen(void *ctx, unsigned int freq,
unsigned int duration)
{
return 0;
}
static void
hostapd_nan_de_discovery_result(void *ctx, int subscribe_id,
enum nan_service_protocol_type srv_proto_type,
const u8 *ssi, size_t ssi_len,
int peer_publish_id, const u8 *peer_addr,
bool fsd, bool fsd_gas)
{
struct hostapd_data *hapd = ctx;
char *ssi_hex;
ssi_hex = os_zalloc(2 * ssi_len + 1);
if (!ssi_hex)
return;
if (ssi)
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_DISCOVERY_RESULT
"subscribe_id=%d publish_id=%d address=" MACSTR
" fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s",
subscribe_id, peer_publish_id, MAC2STR(peer_addr),
fsd, fsd_gas, srv_proto_type, ssi_hex);
os_free(ssi_hex);
}
static void
hostapd_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
int peer_subscribe_id,
enum nan_service_protocol_type srv_proto_type,
const u8 *ssi, size_t ssi_len)
{
struct hostapd_data *hapd = ctx;
char *ssi_hex;
ssi_hex = os_zalloc(2 * ssi_len + 1);
if (!ssi_hex)
return;
if (ssi)
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_REPLIED
"publish_id=%d address=" MACSTR
" subscribe_id=%d srv_proto_type=%u ssi=%s",
publish_id, MAC2STR(peer_addr), peer_subscribe_id,
srv_proto_type, ssi_hex);
os_free(ssi_hex);
}
static const char * nan_reason_txt(enum nan_de_reason reason)
{
switch (reason) {
case NAN_DE_REASON_TIMEOUT:
return "timeout";
case NAN_DE_REASON_USER_REQUEST:
return "user-request";
case NAN_DE_REASON_FAILURE:
return "failure";
}
return "unknown";
}
static void hostapd_nan_de_publish_terminated(void *ctx, int publish_id,
enum nan_de_reason reason)
{
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_PUBLISH_TERMINATED
"publish_id=%d reason=%s",
publish_id, nan_reason_txt(reason));
}
static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
enum nan_de_reason reason)
{
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
"subscribe_id=%d reason=%s",
subscribe_id, nan_reason_txt(reason));
}
static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id,
const u8 *ssi, size_t ssi_len,
const u8 *peer_addr)
{
struct hostapd_data *hapd = ctx;
char *ssi_hex;
ssi_hex = os_zalloc(2 * ssi_len + 1);
if (!ssi_hex)
return;
if (ssi)
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_RECEIVE
"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
os_free(ssi_hex);
}
int hostapd_nan_usd_init(struct hostapd_data *hapd)
{
struct nan_callbacks cb;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = hapd;
cb.tx = hostapd_nan_de_tx;
cb.listen = hostapd_nan_de_listen;
cb.discovery_result = hostapd_nan_de_discovery_result;
cb.replied = hostapd_nan_de_replied;
cb.publish_terminated = hostapd_nan_de_publish_terminated;
cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated;
cb.receive = hostapd_nan_de_receive;
hapd->nan_de = nan_de_init(hapd->own_addr, true, &cb);
if (!hapd->nan_de)
return -1;
return 0;
}
void hostapd_nan_usd_deinit(struct hostapd_data *hapd)
{
nan_de_deinit(hapd->nan_de);
hapd->nan_de = NULL;
}
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
unsigned int freq, const u8 *buf, size_t len)
{
if (!hapd->nan_de)
return;
nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len);
}
void hostapd_nan_usd_flush(struct hostapd_data *hapd)
{
if (!hapd->nan_de)
return;
nan_de_flush(hapd->nan_de);
}
int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
struct nan_publish_params *params)
{
int publish_id;
struct wpabuf *elems = NULL;
if (!hapd->nan_de)
return -1;
publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
ssi, elems, params);
wpabuf_free(elems);
return publish_id;
}
void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id)
{
if (!hapd->nan_de)
return;
nan_de_cancel_publish(hapd->nan_de, publish_id);
}
int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
const struct wpabuf *ssi)
{
int ret;
if (!hapd->nan_de)
return -1;
ret = nan_de_update_publish(hapd->nan_de, publish_id, ssi);
return ret;
}
int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
struct nan_subscribe_params *params)
{
int subscribe_id;
struct wpabuf *elems = NULL;
if (!hapd->nan_de)
return -1;
subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
srv_proto_type, ssi, elems, params);
wpabuf_free(elems);
return subscribe_id;
}
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
int subscribe_id)
{
if (!hapd->nan_de)
return;
nan_de_cancel_subscribe(hapd->nan_de, subscribe_id);
}
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
const struct wpabuf *ssi,
const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id)
{
if (!hapd->nan_de)
return -1;
return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr,
req_instance_id);
}
+46
View File
@@ -0,0 +1,46 @@
/*
* NAN unsynchronized service discovery (USD)
* Copyright (c) 2024, Qualcomm Innovation Center, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef NAN_USD_AP_H
#define NAN_USD_AP_H
struct nan_subscribe_params;
struct nan_publish_params;
enum nan_service_protocol_type;
int hostapd_nan_usd_init(struct hostapd_data *hapd);
void hostapd_nan_usd_deinit(struct hostapd_data *hapd);
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
unsigned int freq, const u8 *buf, size_t len);
void hostapd_nan_usd_flush(struct hostapd_data *hapd);
int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
struct nan_publish_params *params);
void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id);
int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
const struct wpabuf *ssi);
int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
struct nan_subscribe_params *params);
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
int subscribe_id);
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
const struct wpabuf *ssi,
const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id);
void hostapd_nan_usd_remain_on_channel_cb(struct hostapd_data *hapd,
unsigned int freq,
unsigned int duration);
void hostapd_nan_usd_cancel_remain_on_channel_cb(struct hostapd_data *hapd,
unsigned int freq);
void hostapd_nan_usd_tx_wait_expire(struct hostapd_data *hapd);
#endif /* NAN_USD_AP_H */
+1
View File
@@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
list) {
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
dl_list_del(&ip6addr->list);
os_free(ip6addr);
}
}
+59 -15
View File
@@ -24,7 +24,7 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
list) {
if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
if (ether_addr_equal(bssid, nr->bssid) &&
(!ssid ||
(ssid->ssid_len == nr->ssid.ssid_len &&
os_memcmp(ssid->ssid, nr->ssid.ssid,
@@ -99,7 +99,10 @@ 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));
os_memset(&nr->lci_date, 0, sizeof(nr->lci_date));
nr->stationary = 0;
nr->short_ssid = 0;
nr->bss_parameters = 0;
}
@@ -136,7 +139,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
os_memcpy(entry->bssid, bssid, ETH_ALEN);
os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
entry->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
entry->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
entry->nr = wpabuf_dup(nr);
if (!entry->nr)
@@ -165,6 +168,14 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
}
static void hostapd_neighbor_free(struct hostapd_neighbor_entry *nr)
{
hostapd_neighbor_clear_entry(nr);
dl_list_del(&nr->list);
os_free(nr);
}
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid)
{
@@ -174,9 +185,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
if (!nr)
return -1;
hostapd_neighbor_clear_entry(nr);
dl_list_del(&nr->list);
os_free(nr);
hostapd_neighbor_free(nr);
return 0;
}
@@ -188,9 +197,7 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
dl_list_for_each_safe(nr, prev, &hapd->nr_db,
struct hostapd_neighbor_entry, list) {
hostapd_neighbor_clear_entry(nr);
dl_list_del(&nr->list);
os_free(nr);
hostapd_neighbor_free(nr);
}
}
@@ -199,19 +206,21 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
int ht, int vht, int he)
{
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
enum oper_chan_width oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
if (!ht && !vht && !he)
return NR_CHAN_WIDTH_20;
if (!hapd->iconf->secondary_channel)
return NR_CHAN_WIDTH_20;
if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
return NR_CHAN_WIDTH_40;
if (oper_chwidth == CHANWIDTH_80MHZ)
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
return NR_CHAN_WIDTH_80;
if (oper_chwidth == CHANWIDTH_160MHZ)
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
return NR_CHAN_WIDTH_160;
if (oper_chwidth == CHANWIDTH_80P80MHZ)
if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
return NR_CHAN_WIDTH_80P80;
return NR_CHAN_WIDTH_20;
}
@@ -225,6 +234,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -260,10 +270,12 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
if (he)
bssid_info |= NEI_REP_BSSID_INFO_HE;
}
if (he)
bssid_info |= NEI_REP_BSSID_INFO_HE;
if (eht)
bssid_info |= NEI_REP_BSSID_INFO_EHT;
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
@@ -320,3 +332,35 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
wpabuf_free(nr);
#endif /* NEED_AP_MLME */
}
static struct hostapd_neighbor_entry *
hostapd_neighbor_get_diff_short_ssid(struct hostapd_data *hapd, const u8 *bssid)
{
struct hostapd_neighbor_entry *nr;
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
list) {
if (ether_addr_equal(bssid, nr->bssid) &&
nr->short_ssid != hapd->conf->ssid.short_ssid)
return nr;
}
return NULL;
}
int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd)
{
struct hostapd_neighbor_entry *nr;
nr = hostapd_neighbor_get_diff_short_ssid(hapd, hapd->own_addr);
if (!nr)
return -1;
/* Clear old entry due to SSID change */
hostapd_neighbor_free(nr);
hostapd_neighbor_set_own_report(hapd);
return 0;
}
+1
View File
@@ -20,6 +20,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpabuf *civic, int stationary,
u8 bss_parameters);
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
void hostapd_free_neighbor_db(struct hostapd_data *hapd);
+24 -8
View File
@@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
os_free(entry->vlan_desc);
os_free(entry->identity);
os_free(entry->dpp_pkhash);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
@@ -55,7 +56,9 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
unsigned int hash;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
if (pmksa->free_cb)
pmksa->free_cb(entry, pmksa->ctx);
/* unlink from hash list */
hash = PMKID_HASH(entry->pmkid);
@@ -331,6 +334,10 @@ pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
if (kck && kck_len && kck_len < WPA_KCK_MAX_LEN) {
os_memcpy(entry->kck, kck, kck_len);
entry->kck_len = kck_len;
}
if (pmkid)
os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
@@ -480,14 +487,14 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
entry = entry->hnext) {
if ((spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
ether_addr_equal(entry->spa, spa)) &&
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
return entry;
}
} else {
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
ether_addr_equal(entry->spa, spa))
return entry;
}
}
@@ -514,7 +521,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
u8 new_pmkid[PMKID_LEN];
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
if (!ether_addr_equal(entry->spa, spa))
continue;
if (wpa_key_mgmt_sae(entry->akmp) ||
wpa_key_mgmt_fils(entry->akmp)) {
@@ -522,8 +529,17 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
return entry;
continue;
}
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (entry->akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 &&
entry->kck_len > 0)
rsn_pmkid_suite_b_192(entry->kck, entry->kck_len,
aa, spa, new_pmkid);
else if (wpa_key_mgmt_suite_b(entry->akmp) &&
entry->kck_len > 0)
rsn_pmkid_suite_b(entry->kck, entry->kck_len, aa, spa,
new_pmkid);
else
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa,
new_pmkid, entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
}
@@ -559,7 +575,7 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
int match = 0;
if (attr->sta_addr) {
if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
if (!ether_addr_equal(attr->sta_addr, entry->spa))
return 0;
match++;
}
@@ -701,7 +717,7 @@ int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
* <BSSID> <PMKID> <PMK> <expiration in seconds>
*/
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
if (addr && !ether_addr_equal(entry->spa, addr))
continue;
ret = os_snprintf(pos, end - pos, MACSTR " ",
+4
View File
@@ -19,10 +19,14 @@ struct rsn_pmksa_cache_entry {
u8 pmkid[PMKID_LEN];
u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
u8 kck[WPA_KCK_MAX_LEN];
size_t kck_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 spa[ETH_ALEN];
u8 *dpp_pkhash; /* SHA256_MAC_LEN octet hash value of DPP Connector
* public key */
u8 *identity;
size_t identity_len;
struct wpabuf *cui;
+2 -2
View File
@@ -58,7 +58,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
ethhdr = (struct l2_ethhdr *) buf;
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
if (!ether_addr_equal(ethhdr->h_dest, hapd->own_addr)) {
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
MACSTR, MAC2STR(ethhdr->h_dest));
return;
@@ -90,7 +90,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
return;
sta->preauth_iface = piface;
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
len - sizeof(*ethhdr));
len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN);
}
+121
View File
@@ -334,6 +334,53 @@ static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
}
static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data,
void *user_ctx)
{
struct hostapd_data *hapd = eloop_data;
wpa_printf(MSG_DEBUG,
"RRM: Link measurement request (token %u) timed out",
hapd->link_measurement_req_token);
hapd->link_mesr_req_active = 0;
}
static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd,
const u8 *buf, size_t len)
{
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
const struct rrm_link_measurement_report *report;
const u8 *pos, *end;
char report_msg[2 * 8 + 1];
end = buf + len;
pos = mgmt->u.action.u.rrm.variable;
report = (const struct rrm_link_measurement_report *) (pos - 1);
if (end - (const u8 *) report < (int) sizeof(*report))
return;
if (!hapd->link_mesr_req_active ||
(hapd->link_measurement_req_token != report->dialog_token)) {
wpa_printf(MSG_INFO,
"Unexpected Link measurement report, token %u",
report->dialog_token);
return;
}
hapd->link_mesr_req_active = 0;
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
report_msg[0] = '\0';
if (wpa_snprintf_hex(report_msg, sizeof(report_msg),
pos, end - pos) < 0)
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s",
MAC2STR(mgmt->sa), report->dialog_token, report_msg);
}
void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
const u8 *buf, size_t len)
{
@@ -356,6 +403,9 @@ void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
hostapd_handle_nei_report_req(hapd, buf, len);
break;
case WLAN_RRM_LINK_MEASUREMENT_REPORT:
hostapd_handle_link_mesr_report(hapd, buf, len);
break;
default:
wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
mgmt->u.action.u.rrm.action);
@@ -563,6 +613,7 @@ void hostapd_clean_rrm(struct hostapd_data *hapd)
hapd->lci_req_active = 0;
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
hapd->range_req_active = 0;
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
}
@@ -672,3 +723,73 @@ void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
" %u ack=%d", MAC2STR(mgmt->da),
mgmt->u.action.u.rrm.dialog_token, ok);
}
int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr)
{
struct wpabuf *buf;
struct sta_info *sta;
int ret;
wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR,
MAC2STR(addr));
if (!(hapd->iface->drv_rrm_flags &
WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
wpa_printf(MSG_INFO,
"Request Link Measurement: the driver does not support TX power insertion");
return -1;
}
sta = ap_get_sta(hapd, addr);
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
wpa_printf(MSG_INFO,
"Request Link Measurement: specied STA is not connected");
return -1;
}
if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) {
wpa_printf(MSG_INFO,
"Request Link Measurement: destination STA does not support link measurement");
return -1;
}
if (hapd->link_mesr_req_active) {
wpa_printf(MSG_DEBUG,
"Request Link Measurement: request already in process - overriding");
hapd->link_mesr_req_active = 0;
eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler,
hapd, NULL);
}
/* Action + Action type + token + Tx Power used + Max Tx Power = 5 */
buf = wpabuf_alloc(5);
if (!buf)
return -1;
hapd->link_measurement_req_token++;
if (!hapd->link_measurement_req_token)
hapd->link_measurement_req_token++;
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
wpabuf_put_u8(buf, hapd->link_measurement_req_token);
/* NOTE: The driver is expected to fill the Tx Power Used and Max Tx
* Power */
wpabuf_put_u8(buf, 0);
wpabuf_put_u8(buf, 0);
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
if (ret < 0)
return ret;
hapd->link_mesr_req_active = 1;
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
hostapd_link_mesr_rep_timeout_handler, hapd,
NULL);
return hapd->link_measurement_req_token;
}
+2
View File
@@ -29,5 +29,7 @@ int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
size_t len, int ok);
int hostapd_send_link_measurement_req(struct hostapd_data *hapd,
const u8 *addr);
#endif /* RRM_H */
+395 -74
View File
@@ -92,7 +92,7 @@ struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
if (p2p_dev_addr == NULL)
continue;
if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
if (ether_addr_equal(p2p_dev_addr, addr))
return sta;
}
@@ -140,7 +140,7 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
!ether_addr_equal(s->hnext->addr, sta->addr))
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
@@ -180,13 +180,48 @@ void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
sta->pasn->fils.erp_resp = NULL;
#endif /* CONFIG_FILS */
bin_clear_free(sta->pasn, sizeof(*sta->pasn));
pasn_data_deinit(sta->pasn);
sta->pasn = NULL;
}
}
#endif /* CONFIG_PASN */
static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifdef CONFIG_IEEE80211BE
if (hostapd_sta_is_link_sta(hapd, sta) &&
!hostapd_drv_link_sta_remove(hapd, sta->addr))
return;
#endif /* CONFIG_IEEE80211BE */
hostapd_drv_sta_remove(hapd, sta->addr);
}
#ifdef CONFIG_IEEE80211BE
static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd,
struct sta_info *psta)
{
struct sta_info *lsta;
struct hostapd_data *lhapd;
if (!ap_sta_is_mld(hapd, psta))
return;
for_each_mld_link(lhapd, hapd) {
if (lhapd == hapd)
continue;
lsta = ap_get_sta(lhapd, psta->addr);
if (lsta)
lsta->wpa_sm = NULL;
}
}
#endif /* CONFIG_IEEE80211BE */
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -197,7 +232,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
if ((sta->flags & WLAN_STA_WDS) ||
(sta->flags & WLAN_STA_MULTI_AP &&
(hapd->conf->multi_ap & BACKHAUL_BSS) &&
hapd->conf->wds_sta &&
!(sta->flags & WLAN_STA_WPS)))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (sta->ipaddr)
@@ -206,7 +245,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
if (!hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH)) {
hostapd_drv_sta_remove(hapd, sta->addr);
__ap_free_sta(hapd, sta);
sta->added_unassoc = 0;
}
@@ -287,7 +326,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_MESH */
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
ieee802_11_update_beacons(hapd->iface);
wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
__func__, MAC2STR(sta->addr));
@@ -298,7 +337,23 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
sae_clear_retransmit_timer(hapd, sta);
ieee802_1x_free_station(hapd, sta);
#ifdef CONFIG_IEEE80211BE
if (!ap_sta_is_mld(hapd, sta) ||
hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
/* Remove references from partner links. */
clear_wpa_sm_for_each_partner_link(hapd, sta);
}
/* Release group references in case non-association link STA is removed
* before association link STA */
if (hostapd_sta_is_link_sta(hapd, sta))
wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id);
#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
if (hapd->radius)
@@ -339,6 +394,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_INTERWORKING
if (sta->gas_dialog) {
int i;
for (i = 0; i < GAS_DIALOG_MAX; i++)
gas_serv_dialog_clear(&sta->gas_dialog[i]);
os_free(sta->gas_dialog);
@@ -358,6 +414,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->vht_operation);
os_free(sta->he_capab);
os_free(sta->he_6ghz_capab);
os_free(sta->eht_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -408,8 +465,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ifname_wds);
#ifdef CONFIG_IEEE80211BE
ap_sta_free_sta_profile(&sta->mld_info);
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS
os_free(sta->sae_postponed_commit);
forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(sta);
@@ -436,6 +498,27 @@ void hostapd_free_stas(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211BE
void hostapd_free_link_stas(struct hostapd_data *hapd)
{
struct sta_info *sta, *prev;
sta = hapd->sta_list;
while (sta) {
prev = sta;
sta = sta->next;
if (!hostapd_sta_is_link_sta(hapd, prev))
continue;
wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR,
MAC2STR(prev->addr));
ap_free_sta(hapd, prev);
}
}
#endif /* CONFIG_IEEE80211BE */
/**
* ap_handle_timer - Per STA timer handler
* @eloop_ctx: struct hostapd_data *
@@ -450,6 +533,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
int reason;
int max_inactivity = hapd->conf->ap_max_inactivity;
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
@@ -462,6 +546,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
return;
}
if (sta->max_idle_period)
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
if ((sta->flags & WLAN_STA_ASSOC) &&
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
@@ -483,7 +570,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
* Anyway, try again after the next inactivity timeout,
* but do not disconnect the station now.
*/
next_time = hapd->conf->ap_max_inactivity + fuzz;
next_time = max_inactivity + fuzz;
} else if (inactive_sec == -ENOENT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has lost its driver entry",
@@ -492,20 +579,19 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
/* Avoid sending client probe on removed client */
sta->timeout_next = STA_DISASSOC;
goto skip_poll;
} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
} else if (inactive_sec < max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity + fuzz -
inactive_sec;
next_time = max_inactivity + fuzz - inactive_sec;
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been "
"inactive too long: %d sec, max allowed: %d",
MAC2STR(sta->addr), inactive_sec,
hapd->conf->ap_max_inactivity);
max_inactivity);
if (hapd->conf->skip_inactivity_poll)
sta->timeout_next = STA_DISASSOC;
@@ -521,7 +607,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity;
next_time = max_inactivity;
}
skip_poll:
@@ -709,6 +795,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
int i;
int max_inactivity = hapd->conf->ap_max_inactivity;
sta = ap_get_sta(hapd, addr);
if (sta)
@@ -742,12 +829,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
}
sta->supported_rates_len = i;
if (sta->max_idle_period)
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
__func__, MAC2STR(addr),
hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
max_inactivity);
eloop_register_timeout(max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
@@ -833,12 +923,42 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
}
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
static void ap_sta_disconnect_common(struct hostapd_data *hapd,
struct sta_info *sta, unsigned int timeout)
{
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG,
"reschedule ap_handle_timer timeout (%u sec) for " MACSTR,
MAC2STR(sta->addr), timeout);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(hapd, sta);
#ifdef CONFIG_IEEE80211BE
if (!hapd->conf->mld_ap ||
hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
clear_wpa_sm_for_each_partner_link(hapd, sta);
}
#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
sta->wpa_sm = NULL;
}
static void ap_sta_handle_disassociate(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
/* Skip deauthentication in DMG/IEEE 802.11ad */
@@ -849,20 +969,8 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
sta->timeout_next = STA_DEAUTH;
}
ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
__func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DISASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(hapd, sta);
wpa_auth_sta_deinit(sta->wpa_sm);
sta->wpa_sm = NULL;
ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC);
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
@@ -885,8 +993,8 @@ 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)
static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason)
{
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
@@ -898,21 +1006,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
__func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(hapd, sta);
ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
@@ -923,6 +1021,104 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
}
static bool ap_sta_ml_disconnect(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason,
bool disassoc)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *assoc_hapd, *tmp_hapd;
struct sta_info *assoc_sta;
unsigned int i, link_id;
struct hapd_interfaces *interfaces;
if (!hostapd_is_mld_ap(hapd))
return false;
/*
* Get the station on which the association was performed, as it holds
* the information about all the other links.
*/
assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
if (!assoc_sta)
return false;
interfaces = assoc_hapd->iface->interfaces;
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
if (!assoc_sta->mld_info.links[link_id].valid)
continue;
for (i = 0; i < interfaces->count; i++) {
struct sta_info *tmp_sta;
tmp_hapd = interfaces->iface[i]->bss[0];
if (!hostapd_is_ml_partner(tmp_hapd, assoc_hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
tmp_sta = tmp_sta->next) {
/*
* Handle the station on which the association
* was done only after all other link station
* are removed. Since there is a only a single
* station per hapd with the same association
* link simply break;
*/
if (tmp_sta == assoc_sta)
break;
if (tmp_sta->mld_assoc_link_id !=
assoc_sta->mld_assoc_link_id ||
tmp_sta->aid != assoc_sta->aid)
continue;
if (disassoc)
ap_sta_handle_disassociate(tmp_hapd,
tmp_sta,
reason);
else
ap_sta_handle_deauthenticate(tmp_hapd,
tmp_sta,
reason);
break;
}
}
}
/* Disconnect the station on which the association was performed. */
if (disassoc)
ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason);
else
ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason);
return true;
#else /* CONFIG_IEEE80211BE */
return false;
#endif /* CONFIG_IEEE80211BE */
}
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
if (ap_sta_ml_disconnect(hapd, sta, reason, true))
return;
ap_sta_handle_disassociate(hapd, sta, reason);
}
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
if (ap_sta_ml_disconnect(hapd, sta, reason, false))
return;
ap_sta_handle_deauthenticate(hapd, sta, reason);
}
#ifdef CONFIG_WPS
int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx)
@@ -1066,6 +1262,12 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
struct hostapd_vlan *vlan = NULL;
int ret;
int old_vlanid = sta->vlan_id_bound;
int mld_link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap)
mld_link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
wpa_printf(MSG_DEBUG,
@@ -1123,7 +1325,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id,
mld_link_id);
if (ret < 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
@@ -1251,8 +1454,6 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
for (psk = ssid->wpa_psk; psk; psk = psk->next)
if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
break;
if (!psk)
return NULL;
if (!psk || !psk->keyid[0])
return NULL;
@@ -1260,8 +1461,44 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
}
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
struct sta_info *sta)
{
return wpa_auth_get_dpp_pkhash(sta->wpa_sm);
}
bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return false;
if (authorized) {
int mld_assoc_link_id = -1;
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
if (sta->mld_assoc_link_id == hapd->mld_link_id)
mld_assoc_link_id = sta->mld_assoc_link_id;
else
mld_assoc_link_id = -2;
}
#endif /* CONFIG_IEEE80211BE */
if (mld_assoc_link_id != -2)
hostapd_prune_associations(hapd, sta->addr,
mld_assoc_link_id);
sta->flags |= WLAN_STA_AUTHORIZED;
} else {
sta->flags &= ~WLAN_STA_AUTHORIZED;
}
return true;
}
void ap_sta_set_authorized_event(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
const u8 *dev_addr = NULL;
char buf[100];
@@ -1269,14 +1506,7 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
u8 addr[ETH_ALEN];
u8 ip_addr_buf[4];
#endif /* CONFIG_P2P */
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
if (authorized)
sta->flags |= WLAN_STA_AUTHORIZED;
else
sta->flags &= ~WLAN_STA_AUTHORIZED;
const u8 *ip_ptr = NULL;
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
@@ -1293,15 +1523,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_P2P */
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
sta->addr, authorized, dev_addr);
if (authorized) {
const u8 *dpp_pkhash;
const char *keyid;
char dpp_pkhash_buf[100];
char keyid_buf[100];
char ip_addr[100];
dpp_pkhash_buf[0] = '\0';
keyid_buf[0] = '\0';
ip_addr[0] = '\0';
#ifdef CONFIG_P2P
@@ -1310,6 +1539,7 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
" ip_addr=%u.%u.%u.%u",
ip_addr_buf[0], ip_addr_buf[1],
ip_addr_buf[2], ip_addr_buf[3]);
ip_ptr = ip_addr_buf;
}
#endif /* CONFIG_P2P */
@@ -1319,14 +1549,27 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
" keyid=%s", keyid);
}
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
buf, ip_addr, keyid_buf);
dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
if (dpp_pkhash) {
const char *prefix = " dpp_pkhash=";
size_t plen = os_strlen(prefix);
os_strlcpy(dpp_pkhash_buf, prefix,
sizeof(dpp_pkhash_buf));
wpa_snprintf_hex(&dpp_pkhash_buf[plen],
sizeof(dpp_pkhash_buf) - plen,
dpp_pkhash, SHA256_MAC_LEN);
}
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
buf, ip_addr, keyid_buf, dpp_pkhash_buf);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED "%s%s%s",
buf, ip_addr, keyid_buf);
AP_STA_CONNECTED "%s%s%s%s",
buf, ip_addr, keyid_buf,
dpp_pkhash_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
@@ -1336,6 +1579,11 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
AP_STA_DISCONNECTED "%s", buf);
}
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
sta->addr, authorized, dev_addr,
ip_ptr);
#ifdef CONFIG_FST
if (hapd->iface->fst) {
if (authorized)
@@ -1348,6 +1596,15 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
}
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
if (!ap_sta_set_authorized_flag(hapd, sta, authorized))
return;
ap_sta_set_authorized_event(hapd, sta, authorized);
}
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason)
{
@@ -1461,7 +1718,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
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%s%s%s",
"%s%s%s%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]" : ""),
@@ -1481,6 +1738,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_EHT ? "[EHT]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1512,11 +1770,12 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta)
struct sta_info *sta,
unsigned timeout)
{
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"IEEE 802.1X: Force disconnection of " MACSTR
" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
" after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
/*
* Add a small sleep to increase likelihood of previously requested
@@ -1524,8 +1783,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
* 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);
eloop_register_timeout(0, timeout * 1000,
ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
}
@@ -1537,8 +1796,37 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
}
#ifdef CONFIG_IEEE80211BE
static void ap_sta_remove_link_sta(struct hostapd_data *hapd,
struct sta_info *sta)
{
struct hostapd_data *tmp_hapd;
for_each_mld_link(tmp_hapd, hapd) {
struct sta_info *tmp_sta;
if (hapd == tmp_hapd)
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
tmp_sta = tmp_sta->next) {
if (tmp_sta == sta ||
!ether_addr_equal(tmp_sta->addr, sta->addr))
continue;
ap_free_sta(tmp_hapd, tmp_sta);
break;
}
}
}
#endif /* CONFIG_IEEE80211BE */
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
{
const u8 *mld_link_addr = NULL;
bool mld_link_sta = false;
/*
* If a station that is already associated to the AP, is trying to
* authenticate again, remove the STA entry, in order to make sure the
@@ -1546,6 +1834,22 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
* this, station's added_unassoc flag is cleared once the station has
* completed association.
*/
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
u8 mld_link_id = hapd->mld_link_id;
mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
/*
* In case the AP is affiliated with an AP MLD, we need to
* remove the station from all relevant links/APs.
*/
ap_sta_remove_link_sta(hapd, sta);
}
#endif /* CONFIG_IEEE80211BE */
ap_sta_set_authorized(hapd, sta, 0);
hostapd_drv_sta_remove(hapd, sta->addr);
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
@@ -1553,8 +1857,9 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
0, NULL, NULL, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0)) {
0, NULL, NULL, NULL, 0, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0,
mld_link_addr, mld_link_sta)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
@@ -1565,3 +1870,19 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
sta->added_unassoc = 1;
return 0;
}
#ifdef CONFIG_IEEE80211BE
void ap_sta_free_sta_profile(struct mld_info *info)
{
int i;
if (!info)
return;
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
os_free(info->links[i].resp_sta_profile);
info->links[i].resp_sta_profile = NULL;
}
}
#endif /* CONFIG_IEEE80211BE */
+65 -31
View File
@@ -16,6 +16,8 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha384.h"
#include "pasn/pasn_common.h"
#include "hostapd.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -42,6 +44,7 @@
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
#define WLAN_STA_EHT BIT(27)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -64,43 +67,34 @@ struct mbo_non_pref_chan_info {
struct pending_eapol_rx {
struct wpabuf *buf;
struct os_reltime rx_time;
enum frame_encryption encrypted;
};
enum pasn_fils_state {
PASN_FILS_STATE_NONE = 0,
PASN_FILS_STATE_PENDING_AS,
PASN_FILS_STATE_COMPLETE
};
#define EHT_ML_MAX_STA_PROF_LEN 1024
struct mld_info {
bool mld_sta;
struct pasn_fils_data {
u8 state;
u8 nonce[FILS_NONCE_LEN];
u8 anonce[FILS_NONCE_LEN];
u8 session[FILS_SESSION_LEN];
u8 erp_pmkid[PMKID_LEN];
struct ml_common_info {
u8 mld_addr[ETH_ALEN];
u16 medium_sync_delay;
u16 eml_capa;
u16 mld_capa;
} common_info;
struct wpabuf *erp_resp;
};
struct mld_link_info {
u8 valid:1;
u8 nstr_bitmap_len:2;
u8 local_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN];
struct pasn_data {
int akmp;
int cipher;
u16 group;
u8 trans_seq;
u8 wrapped_data_format;
size_t kdk_len;
u8 nstr_bitmap[2];
u8 hash[SHA384_MAC_LEN];
struct wpa_ptk ptk;
struct crypto_ecdh *ecdh;
u16 capability;
struct wpabuf *secret;
#ifdef CONFIG_SAE
struct sae_data sae;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
struct pasn_fils_data fils;
#endif /* CONFIG_FILS */
u16 status;
u16 resp_sta_profile_len;
u8 *resp_sta_profile;
} links[MAX_NUM_MLD_LINKS];
};
struct sta_info {
@@ -152,6 +146,7 @@ struct sta_info {
unsigned int qos_map_enabled:1;
unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
unsigned int hs20_deauth_on_ack:1;
unsigned int session_timeout_set:1;
unsigned int radius_das_match:1;
unsigned int ecsa_supported:1;
@@ -213,6 +208,8 @@ struct sta_info {
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
struct ieee80211_eht_capabilities *eht_capab;
size_t eht_capab_len;
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
@@ -330,6 +327,14 @@ struct sta_info {
#ifdef CONFIG_PASN
struct pasn_data *pasn;
#endif /* CONFIG_PASN */
#ifdef CONFIG_IEEE80211BE
struct mld_info mld_info;
u8 mld_assoc_link_id;
#endif /* CONFIG_IEEE80211BE */
u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
* units of 1000 TUs */
};
@@ -385,9 +390,15 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta);
const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta,
int authorized);
void ap_sta_set_authorized_event(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
void ap_sta_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
static inline int ap_sta_is_authorized(struct sta_info *sta)
@@ -402,11 +413,34 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
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);
struct sta_info *sta,
unsigned timeout);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
static inline bool ap_sta_is_mld(struct hostapd_data *hapd,
struct sta_info *sta)
{
#ifdef CONFIG_IEEE80211BE
return hapd->conf->mld_ap && sta && sta->mld_info.mld_sta;
#else /* CONFIG_IEEE80211BE */
return false;
#endif /* CONFIG_IEEE80211BE */
}
static inline void ap_sta_set_mld(struct sta_info *sta, bool mld)
{
#ifdef CONFIG_IEEE80211BE
if (sta)
sta->mld_info.mld_sta = mld;
#endif /* CONFIG_IEEE80211BE */
}
void ap_sta_free_sta_profile(struct mld_info *info);
void hostapd_free_link_stas(struct hostapd_data *hapd);
#endif /* STA_INFO_H */

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