wpa: Import wpa 2.11
This commit is contained in:
+1
-1
@@ -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,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
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.config
|
||||
hostapd
|
||||
hostapd_cli
|
||||
hlr_auc_gw
|
||||
nt_password_hash
|
||||
-1155
File diff suppressed because it is too large
Load Diff
-1321
File diff suppressed because it is too large
Load Diff
-1378
File diff suppressed because it is too large
Load Diff
-354
@@ -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
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -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
@@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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?)
|
||||
@@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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'
|
||||
@@ -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).
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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]
|
||||
@@ -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
|
||||
);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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#
|
||||
@@ -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
|
||||
@@ -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
@@ -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/
|
||||
@@ -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);
|
||||
@@ -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
@@ -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(¶ms, 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, ¶ms);
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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], ¶ms);
|
||||
os_free(params.freqs);
|
||||
|
||||
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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 AP’s 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
@@ -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, ¶ms);
|
||||
}
|
||||
|
||||
@@ -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, ¶ms);
|
||||
}
|
||||
@@ -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(¶ms, 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(¶ms, 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, ¶ms);
|
||||
}
|
||||
#endif /* CONFIG_PASN */
|
||||
|
||||
+73
-11
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) */
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+163
-6
@@ -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
@@ -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, ¶ms);
|
||||
|
||||
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], ¶ms);
|
||||
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, ¶ms);
|
||||
|
||||
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], ¶ms);
|
||||
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);
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+75
-8
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 " ",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user