Compare commits

..

168 commits

Author SHA1 Message Date
Michael-CY Lee
bde17063d5 hostapd: Do not indicate a punctured secondary channel in HT operation
If the secondary channel is punctured, the HT operation in the Beacon
frames should not indicate a secondary channel offset.

Co-developed-by: Money Wang <money.wang@mediatek.com>
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
2024-09-01 16:39:57 +03:00
Sergey Matyukevich
809d9d8172 macsec_linux: Hardware offload requires Linux headers >= v5.7
Hardware offload in Linux macsec driver is enabled in compile time if
libnl version is >= v3.6. This is not sufficient for successful build
since enum 'macsec_offload' has been added to Linux header if_link.h
in kernels v5.6 and v5.7, see commits:
- 21114b7fee
- 76564261a7

New libnl with older Linux headers is a valid combination. This is how
hostapd build failure has been detected by Buildroot autobuilder, see:
- http://autobuild.buildroot.net/results/b59d5bc5bd17683a3a1e3577c40c802e81911f84/

Extend compile time condition for the enablement of the macsec hardware
offload adding Linux headers version check.

Fixes: 40c1396644 ("macsec_linux: Add support for MACsec hardware offload")
Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
2024-09-01 16:36:11 +03:00
Jouni Malinen
3ab781fb29 tests: DPP and SAE password identifier
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-09-01 16:33:26 +03:00
Jouni Malinen
0012c4433c DPP: Support for provisioning SAE password identifiers (Configurator)
Allow SAE password identifiers to be provisioned to Enrollees that
indicate support for this capability.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-09-01 16:32:39 +03:00
Dan Harkins
782c89c359 DPP: Support for provisioning SAE password identifiers (Enrollee)
DPP supports provisioning of SAE password identifiers to uniquely
identify a password if the enrollee indicates support for them. Indicate
Enrollee support for that and add the received value into the network
profile.

I put everything under defines for CONFIG_DPP3 as this is a bleeding
edge feature in DPP.

This was tested against my DPP reference implementation acting as the
Configurator.

Signed-off-by: Dan Harkins <dharkins@lounge.org>
2024-09-01 16:06:18 +03:00
Cermak Dominik
de40e08f70 nl80211: Pass "global" events to all interfaces
We got connection failures because of outdated channel information.
That's because the NL80211_CMD_REG_CHANGE event is important for all
interfaces.

Commit f136837202 ("nl80211: Pass wiphy events to all affected
interfaces") skips the early termination for events directed to a wiphy,
but that doesn't cover the regulatory change event because it doesn't
have a wiphy set either. Therefore the early termination still kicks in
and from three interfaces, only one got the updated channel list.

Fix this by changing the early termination logic to only apply to events
directed either to a specific interface index for wdev.

Signed-off-by: Dominik Cermak <dominik.cermak@joynext.com>
2024-09-01 15:39:36 +03:00
Jouni Malinen
c3ee46bcbe AP MLD: Check SAE message length without depending on pointer arithemetic
The way this was checked previously used pointer arithmetic could result
in undefined behavior due to the pointer ending up pointing more than
one byte beyond the end of the buffer. Avoid this by checking the buffer
length before incrementing the pointer.

Fixes: bcbe80a66a ("AP: MLO: Handle Multi-Link element during authentication")
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-09-01 13:24:29 +03:00
Jouni Malinen
63df62c6c0 AP MLD: Work around delayed STA entry addition for SAE confirm
The driver is expected to have an STA entry for a non-AP MLD ready to
translate the address fields for SAE confirm messages. However, there is
at least a theoretical race condition in a case where the peer sends the
SAE confirm message quickly enough for the driver translation mechanism
to not be available to update the SAE confirm message addresses. Work
around that by searching for the STA entry using the link address of the
non-AP MLD if no match is found based on the MLD MAC address.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-09-01 13:14:12 +03:00
Aditya Kumar Singh
f3fd2f699f tests: AP MLD control socket connectivity test case
Add a simple test case to bring up a two link AP MLD and get the status
of each link via the MLD level control socket.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-09-01 12:09:46 +03:00
Aditya Kumar Singh
14cb3906af AP MLD: Introduce MLD level control interface socket
With MLO, each link have socket created with "<ifname>_link<link id>"
under the control interface directory.

Introduce a MLD level socket "<ifname>" as well under the same control
interface directory. This socket can be used to pass the command to its
partner links directly instead of using the link level socket. Link ID
needs to be passed with the command in a prefix way. If no Link ID is
provided the first link ID is selected.

The structure of the command is -
 "LINKID <link id> <COMMAND APPLICABALE FOR THE LINK>"

Directory looks something like this -
  $ ls /var/run/hostapd/
    wlan0
    wlan0_link0
    wlan0_link1

wlan0 here is the MLD level socket. Rest are each link level sockets.

This also helps to maintain backwards compatibility with applications
which looks for <ifname> under the control interface directory.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-09-01 11:49:00 +03:00
Aditya Kumar Singh
757d8d9aac tests: MLO: Use link ID to access control sockets
With MLO, each BSS will create sockets under the given ctrl_iface
directory with the socket name being '<ifname>_link<link_ID>'.

Make necessary changes in MLO related test cases so that it can access
the new socket and proceed further as expected.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-09-01 11:17:11 +03:00
Karthikeyan Kathirvel
61dfd7ae35 AP MLD: Create link based hostapd control sockets
Create link based control sockets to access the link based commands
through hostapd_cli. This will create the link interfaces in the name of
<ifname>_link<X>

Example:
To fetch link 0 status from wlan0, below command can be used -
    $ hostapd_cli -i wlan0 -l 0 status

On failure of link/interface selection, below error will be observed
    $ hostapd_cli -i wlan0 -l 2 status
    Failed to connect to hostapd - wpa_ctrl_open: No such file or directory

Signed-off-by: Karthikeyan Kathirvel <quic_kathirve@quicinc.com>
Co-developed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-09-01 11:17:03 +03:00
Jouni Malinen
8625001ce5 tests: Clear scan cache in wifi_display_parsing
This is needed to avoid false failures if an old BSS entry is still
present for dev[0]. This could happen, e.g., with the following test
case sequence: wpas_mesh_max_peering wifi_display_parsing

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-29 20:21:31 +03:00
Shivani Baranwal
b7963348cd Add QCA vendor attribute to disable channel switch initiation
Add a test config u8 attribute to disable the channel switch
initiation in P2P GO mode.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-29 20:11:06 +03:00
Jouni Malinen
d15403aefb tests: Make rsn_override_mld_too_long_elems more robust
Wait longer for the disconnection event since the previous wait was
exactly the same length as the authentication timeout in wpa_supplicant
and as such, subject to race conditions.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-29 20:10:22 +03:00
Jouni Malinen
3935d78e7b tests: More robust error handling for wifi_display_parsing
Check explicitly that wfd_subelems is present in the dict instead of
failing on a key error when trying to fetch it.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-29 20:10:22 +03:00
Lo,Chin-Ran
2b7277d3f0 USD: Move control interface events to notify.c
This separates the control interface specific generation of a text event
message away from the main implementation of USD and makes it more
convenient to add support for other control interface mechanisms like
dbus.

Signed-off-by: Lo,Chin-Ran <chin-ran.lo@nxp.com>
2024-08-28 11:24:11 +03:00
Vinay Gannevaram
97c6ef2588 QCA vendor interface to set the P2P mode configuration
Add the QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE for setting the P2P mode
in which the P2P Group Owner (GO) should be brought up. These modes
include Wi-Fi Direct R1 only, Wi-Fi Direct R2 only, and P2P Connection
Compatibility Mode, which supports both R1 and R2. These modes are
defined in the enum qca_wlan_vendor_p2p_mode.

Signed-off-by: Vinay Gannevaram <quic_vganneva@quicinc.com>
2024-08-28 00:11:42 +03:00
Kiran Kumar Lokere
e33acc2178 Add QCA vendor attribute to change P2P GO beacon interval
Add new QCA vendor attribute to configure the P2P GO beacon interval
dynamically while the BSS continues operating.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-28 00:05:12 +03:00
Shivani Baranwal
59299a8a7d P2P2: Add bootstrapping support with PD frames
Add support for P2P2 bootstrapping with comeback mechanism using
Provision Discovery frames. Extend the control interface command
P2P_CONNECT to allow P2P2 bootstrapping handshake.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 23:50:20 +03:00
Shivani Baranwal
6aa9ad8f8f P2P2: Refactor provision discovery request/response processing
Parse the P2P IEs in functions that handle provision discovery request
and response. Process the frames based on the IEs received in the PD
frames. This makes it easier to extend PD for P2P2 cases.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
b4f9742ee2 P2P2: Process Element container attribute from NAN SDFs
Process the Element Container attribute from NAN SDF frames and check if
P2P attributes are present. Add a P2P peer device entry if the NAN SDF
frame has matching service and P2P capabilities.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
fa389f2a3b P2P2: Parse P2P2 IE
Add parsing of the P2P2 IE similarly to the way the P2P IE is parsed.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
25c6598f30 NAN USD: Add publishChannelList option for Subscriber
Add frequency list to active NAN USD Subscriber to search for a
Publisher on multiple channels. This is the publish channel list used by
the Subscriber to periodically search for a service on these channels.
publishChannelList was already supported in the Publisher and this
commit extends that to the Subscriber.

This is needed for a P2P2 seeker that is an active subscriber looking
for an advertiser on a list of publish channels.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
bcab29a78c P2P2: Device Identity Key generation and storage in configuration
Generate a random device identity key and save it to the config file.
Use the same identity key from config to derive DIRA for NAN SDF frames.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
58ba550c53 FT: Fix writing of ft_prepend_pmkid configuration parameter
This was missing a newline at the end of the line.

Fixes: 8fa52a7974 ("FT: Allow wpa_supplicant to be configured to prepend PMKR1Name")
Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
5b0112a185 P2P2: Add DIRA attributes to P2P2 IE of NAN SDFs
Add DIRA attribute in P2P2 IE of NAN Subscribe and Publish frames
to enable support for device identity of paired peers.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
29f70292e5 P2P2: Add PCEA and PBMA attributes to P2P2 IE of NAN SDFs
Add PCEA and PBMA attribute in P2P2 IE of NAN Subscribe and Publish frames
to include the P2P2 capabilities and bootstrapping methods.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
a58b2ba2fc P2P2: Allow P2P IE to be added into NAN SDFs
Extend the NAN Subscribe and Publish methods to allow p2p=1 to be
specified to include P2P attributes in a P2P IE to be added into the NAN
Element Container attribute. In addition, use the P2P Device Address for
the NAN SDFs for the P2P cases.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:56 +03:00
Shivani Baranwal
ae221945f6 P2P2: New element and attribute definitions
Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 10:51:53 +03:00
Shivani Baranwal
633e969311 NAN: Option to offload NAN DE for USD into the driver
Support implementation architecture where the NAN discovery engine is
located in the driver/firmware instead of wpa_supplicant.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
2024-08-27 00:26:46 +03:00
Jouni Malinen
87c6b322ee tests: AP MLD and RSN overriding with too long elements
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-23 18:42:55 +03:00
Jouni Malinen
d984172189 RSNO: Check that RSNOE/RSNO2E/RSNXOE fit into RSN Override Link KDE
While these elements fit without issue in production use cases, it is
possible to override the elements for testing purposes and if such
overridden elements are overly long, they would nto fit into the maximum
length RSN Override Link KDE. This could result in difficult to debug
failure cases, so check for this explicitly and instead of sending out
the invalid M3, report the internal issue in the debug log and do not
send M3.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-23 18:40:53 +03:00
Jouni Malinen
c6a8db47c3 tests: RSNXE extensibility
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-23 10:09:10 +03:00
Jouni Malinen
c03edfd5bd Allow IE overriding to use maximum element length
Elements can actually be 257 octets long (2 octets of header followed by
255 octets of payload). The maximum length for various IE override
testing parameters had somehow ended up being one octet too short to
cover the maximum. Increase this to allow the maximum element length to
be reached for testing purposes.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-23 10:07:19 +03:00
Jouni Malinen
7683ce1cff tests: Fix EHT 320 MHz tests to clear sae_groups
These test cases could fail if they happened to be executed after a test
case that set a specific SAE group.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 12:09:20 +03:00
Shivam Rai
d9bb64914a PASN: Add a function to configure noauth variable
When the PASN implementation is used as a library for Wi-Fi Aware
applications there is need to allow the Responder to set the noauth
parameter to support opportunistic pairing method using PASN AKMP. Add
pasn_set_noauth() to address this.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 11:36:02 +03:00
Shivam Rai
8f21cdf9d7 PASN: Add support to reject PASN auth 1 based on user input
When the PASN implementation is used as a library for Wi-Fi Aware
applications there is need to reject the PASN auth 1 frame based on the
user input. Add support to send PASN auth 2 with failure status for
auth 1 frame received to address this need.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 11:28:19 +03:00
Jouni Malinen
18116e38a2 tests: DPP and SAE with short password
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 11:27:00 +03:00
Jouni Malinen
882bd2edd5 DPP: Do not restrict SAE password length on Enrollee
The restriction of the passphrase length to 8..63 characters is only
applicable for WPA2-Personal (PSK). Remove this constraint when
processing a configuration object that includes SAE without PSK.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 11:26:53 +03:00
Jouni Malinen
503e22025b DPP: Do not restrict SAE password length on Configurator
The restriction of the passphrase length to 8..63 characters is only
applicable for WPA2-Personal (PSK). Remove this constraint when
provisioning a configuration object that includes SAE without PSK.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-22 11:20:20 +03:00
Jouni Malinen
064a46b478 tests: RSN overriding and WPA3-Personal Compatibility Mode
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-20 19:31:00 +03:00
Jouni Malinen
9da9e41612 tests: RSN overriding enabled only on the STA
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-15 20:45:55 +03:00
Veerendranath Jakkam
df8c5e22d7 RSNO: Always enable SNonce cookie and RSN Override elements validation
Always set SNonce cookie and enable RSN Override elements validation
irrespective of the RSN Selection element usage in (Re)Association
Request frame when RSN overriding supported.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-15 20:45:55 +03:00
Veerendranath Jakkam
bbb55af8c3 RSNO: Skip validating RSN Override elements with MLO when RSN overriding not used
STA needs to skip validating RSN Override elements when RSN overriding
is not used since AP will not send RSN Override elements in EAPOL-Key
message 3/4. This is handled correctly in non-MLO case but in MLO case
wpa_supplicant always validates RSN Override link KDEs. Fix validating
RSN Override elements in MLO case as well.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-15 20:45:55 +03:00
Jouni Malinen
66d8ac8ccc RSNO: Do not enforce SNonce cookie and RSN Selection match if RSNO not used
A STA that supports RSN overriding will always use the SNonce cookie. An
AP that does not advertise RSN overriding elements must not enforce that
SNonce cookie is used with RSN Selection element since a STA includes
the latter only when it sees the AP advertising RSN overriding elements.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-15 20:45:55 +03:00
Veerendranath Jakkam
70b8f64faf RSNO: Update RSN overriding capability indication to the driver
Modify wpa_supplicant code based on the updated driver interface for RSN
overriding capability indication.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-14 00:47:31 +03:00
Jouni Malinen
5fd3d05a40 More detailed documentation for QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES
Be more specific on how the QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS attribute
is used in the response.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-14 00:47:31 +03:00
Veerendranath Jakkam
fd72d395db QCA vendor interface for indicating supplicant support for RSN overriding
Add QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT to send additional information
such as RSN overriding support of the supplicant for the (re)association
attempts with NL80211_CMD_CONNECT.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-14 00:47:31 +03:00
Veerendranath Jakkam
88150522ce Use QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA only for indicating driver support
Use separate interfaces for indicating driver and supplicant RSN
overriding support. Modifying this interface is fine since this feature
is still under development.

Subsequent commit will define the interface for indicating supplicant
RSN overriding support to the driver.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-14 00:47:28 +03:00
Aditya Kumar Singh
bc5d3bf623 tests: Enable MLD GTK rekey test
Now that MLO GTK rekey support is added, enable the test case fully.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-13 19:24:12 +03:00
Aditya Kumar Singh
8c9b9ccb49 AP MLD: Fix PN/IPN/BIPN for group rekeying
wpa_auth_get_seqnum() for ML group rekeying needs to be skipped in the
same way as it is done for non-ML cases to avoid indicating old values
and resulting in group frames being dropped as replays. The simple check
for gsm->wpa_group_state != WPA_GROUP_SETKEYS (as is done for non-ML) is
not sufficient for this since the per-link Authenticator states are not
strictly synchronized and the state change happens in the middle of this
step.

Fixes: 137b855092 ("MLO: Mechanism for fetching group key information for the links")
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-13 19:24:12 +03:00
Rameshkumar Sundaram
7275b65149 AP MLD: Fix ML STA wpa_group update during rekey
At present, group key update is not confined only on the association
link as originally intended. Hence, ensure now that the group key update
is only performed on the association link for non-AP MLDs.

This was missed during adding support for group rekeying for MLO.

Fixes: 12acda633b ("AP MLD: Support group rekeying for MLO")
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-13 12:59:40 +03:00
Jouni Malinen
5dbbca24ea tests: Group rekeying with VLANs
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-13 12:58:45 +03:00
Jouni Malinen
19e12d5e2d Fix GKeyDoneStations tracking for VLAN
The AP MLD change to use a helper function for this broke the design
that depends on the value for sm->group (i.e., the currently assigned
VLAN) being used instead of the sm->wpa_auth->group. Restore previous
behavior to fix GKeyDoneStations tracking when VLANs are used.

Fixes: 78adbf2c08 ("AP MLD: Mark GKeyDone completed for STAs in a helper function")
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-13 12:58:45 +03:00
Jouni Malinen
189972d129 tests: Fix duplicate test case name
The new test case for an AP MLD in a bridge was supposed to use a unique
test name to avoid hiding an existing test case.

Fixes: c4f9279267 ("tests: AP MLD with two links in a bridge")
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-13 11:44:09 +03:00
Radha Krishna Simha Jiguru
43943ea5b3 nl80211: Add AP_VLAN interface to bridge after interface is up
In the current hostapd flow, AP_VLAN net device is added to a bridge
before the interface is brought up.

Interface up event is used in mac80211 layer for setting device context
in the driver. Vendor specific datapath offload configurations for net
device might also be set up in interface up event context. Adding
AP_VLAN interface to a bridge before the UP event could cause
inconsistent state for datapath offload context setup in a vendor
driver.

Change the sequence to add AP_VLAN interface to a bridge after the
interface is set up. This makes the interface up and bridge add sequence
for AP_VLAN to be consistent with that of a regular AP interface.

Signed-off-by: Radha Krishna Simha Jiguru <quic_rjiguru@quicinc.com>
2024-08-12 12:40:03 +03:00
Jouni Malinen
c4f9279267 tests: AP MLD with two links in a bridge
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-12 12:11:39 +03:00
Karthikeyan Kathirvel
7e7e43d6b3 AP MLD: Add links to bridge FDB for FT roaming
During FT, RRB messages are getting dropped at bridge on an AP MLD since
bridge doesn't know all the link address, so roaming gets failed.

Add AP MLD's each link address to the bridge FDB, so that RRB frames
get forwarded through bridge to hostapd.

Co-developed-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Karthikeyan Kathirvel <quic_kathirve@quicinc.com>
2024-08-12 12:02:00 +03:00
Jouni Malinen
1282787878 tests: hostapd error path on driver interface initialization failure
Signed-off-by: Jouni Malinen <j@w1.fi>
2024-08-10 11:12:07 +03:00
Jintao Lin
015f6a5a0c nl80211: NULL pointer check for link before use
bss->flink could be NULL when wpa_driver_nl80211_del_beacon() is called
if wpa_driver_nl80211_drv_init() fails early through the 'failed' label
and jumps to wpa_driver_nl80211_deinit() with bss->flink unset.

Fixes: 47269be36e ("nl80211: Refactor i802_bss to support multiple links")
Signed-off-by: Jintao Lin <jintaolin@chromium.org>
2024-08-10 11:11:53 +03:00
Aditya Kumar Singh
3e2758b19a hostapd: Avoid channel selection across underlying hardware index
Currently, channel is selected from the current hw_mode. However, not
all channels under current hw_mode might be available for the current
operating underlying hardware.

Add logic to check if the selected channel falls under the current
operating hardware index and only if so, continue with the selected
channel.

Co-developed-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 22:25:02 +03:00
Aditya Kumar Singh
15bf093b5b hostapd: Fetch multiple radios information from the driver
When a driver consolidates several hardware components under a single
radio, it provides details about these components via the
NL80211_CMD_GET_WIPHY command.

Parse this information and store it. A subsequent change will use this
information for validation in certain scenarios.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 22:20:24 +03:00
Jouni Malinen
c43e1e5a5f Sync with wireless-next.git include/uapi/linux/nl80211.h
This brings in nl80211 definitions as of 2024-07-09.

Signed-off-by: Jouni Malinen <j@w1.fi>
2024-08-09 21:58:05 +03:00
Ganesh Kariganuru Mahabalesh
c3beaf6b86 nl80211: MLD: Fix is_shared_drv ops logic when num links is one
Whenever there is only one BSS left and if the number of links is one,
is_shared_drv() returns false assuming no one else is sharing the driver
interface. However, when the number of links is one, this does not
guarantee that the caller's link ID is the only active link ID. If this
is not the case and false is returned, the caller calls hapd_deinit()
which will free the driver interface. However, when the actual active
link_id reaches deinit path, this leads to dereferencing a NULL pointer
ultimately leading to segmentation fault.

To prevent this, pass the link ID into the is_drv_shared() ops and match
it with only with active link IDs. Only return false if they are same.

Signed-off-by: Ganesh Kariganuru Mahabalesh <quic_gkarigan@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 10:05:39 +03:00
Aditya Kumar Singh
3e420372e7 nl80211: Remove unused function argument from is_drv_shared() ops
The bss_ctx argument was never used and can be removed.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:56:51 +03:00
Naveen S
c6ff28cb63 AP MLD: Handle garbage pointer after MLD interface is deleted
In function driver_nl80211_link_remove(), when there is no active links,
interface is removed. This will free the BSS pointer. A copy of the BSS
pointer is also stored in each of the affiliated links' hapd->drv_priv
member.

driver_nl80211_link_remove() is called via multiple paths, e.g., via
NL80211_CMD_STOP_AP and via driver_nl80211_ops. When called when
handling an nl80211 event, links will be removed and when count reaches
zero, the interface will be removed. However, core hostapd will be
unaware of this removal. Hence, if it tries to access its drv_priv
pointer, this can lead to segmentation fault at times since the pointer
is now pointing to freed memory.

Prevent this by adding a new notification event
(EVENT_MLD_INTERFACE_FREED). Whenever the interface is freed, this
notification will be sent. hostapd will process this notification and
will set all affliated links' hapd->drv_priv to NULL.

Signed-off-by: Naveen S <quic_naves@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:56:22 +03:00
Aditya Kumar Singh
e1bf37022e nl80211: MLO: Process stop AP event on link basis
Currently, a stop AP event is processed always on the first BSS in the
drv. However, with multi-link operation, it can come on any interface
and there is need to process it for the intended BSS. Also, the event
has a link ID attribute during MLO which is not used and still the event
is passed to the first link BSS.

Process the event for the intended BSS and for the intended link BSS
during MLO.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:49:04 +03:00
Aditya Kumar Singh
f519f472e6 nl80211: Make nl80211_remove_link() non-static
No functionality changes.

This is needed to support STOP_AP events for MLD interface in a
subsequent change.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:44:18 +03:00
Aditya Kumar Singh
2d290f1966 AP MLD: Handle driver events for interface enable/disable
When an interface is enabled, keys are reconfigured, if required, and
beaconing is started again. With MLO, this needs to be done for each of
the affiliated links. Before starting the beaconing, the link needs to
be added back first.

Similarly, when the interface is disabled, hostapd removes the keys and
set the BSS state to disabled. However, for an AP MLD interface, this
needs to be done for each of the affiliated link BSS.

Handle the interface enable/disable driver event for AP MLD.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:42:59 +03:00
Aditya Kumar Singh
e9984e3db2 hostapd: Refactor interface enable/disable into separate helper functions
Driver events for interface enable/disable are currently handled on
interface level with one hostapd_data instance under consideration. In
order to extend it for MLO, this needs to be done for each of the
affiliated links. Hence, refactor the code into a helper function which
can be used later.

No functionality change. Support for MLO will be added in a subsequent
change.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-09 09:36:02 +03:00
Veerendranath Jakkam
8324947a67 RSNO: Add debug prints for RSN override elements in EAPOL frames
Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-08 22:39:39 +03:00
Veerendranath Jakkam
abd7f47958 RSNO: Fix storing RSNE/RSNXE variants to wpa_sm from association event
Store the full set of AP's RSNE/RSNXE variants to wpa_sm while
processing association event. Commit 521374b978 did this for the cases
that were needed for SME-in-wpa_supplicant cases, but forgot to update
the cases needed for SME-in-driver. Convert those to the updated
protocol design as well.

Fixes: 521374b978 ("RSNO: Include all RSNE/RSNXE variants in EAPOL-Key message 3/4")
Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-08 22:34:03 +03:00
Yu Zhang(Yuriy)
72ac0ee026 WNM: Extend workaround for broken AP operating class behavior
Some APs do not advertise operating classes correctly for BSS Transition
Management. Try to determine the most likely operating frequency based
on the channel number (1..14 --> 2.4 GHz; 36..177 --> 5 GHz) if invalid
op_class == 255 is received in a BSS Transition Management Request. This
speeds up the following operating by avoiding a full scan due to an
unknown channel.

This extends the workaround that was added in commit 80ce804e88 ("WNM:
Workaround for broken AP operating class behavior") for invalid
operating class 0 to cover another observed case with invalid operating
class 255.

Signed-off-by: Yu Zhang(Yuriy) <quic_yuzha@quicinc.com>
2024-08-08 22:26:53 +03:00
Aditya Kumar Singh
e900bcb149 tests: Add CSA support on non-first link of AP MLD
Currently MLO CSA test case supports CSA only on the first link.
However, now it can be extended to other links as well.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-08 22:18:49 +03:00
Aditya Kumar Singh
e33a55d31d nl80211: Sanitize link ID in mlme_event_ch_switch() for AP interface
During channel switch handling for AP MLD, if link ID is incorrect,
there is no point in proceeding till end and failing or returning from
there. Hence sanitize it in the initial time itself and return if it is
incorrect. Throw a warning print if it is not correct as well.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-08 22:18:49 +03:00
Aditya Kumar Singh
de2ee083e7 nl80211: Add ifname and link ID debug prints in mlme_event_ch_switch()
This makes it easier to debug AP MLD behavior.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-08 22:18:49 +03:00
Aloka Dixit
bd8a1f5ff5 hostapd: Enable HE when EHT is set for channel switch
Channel switch operation fails if 'eht' option is given without 'he'
as hostapd_config_check() returns following error:
"Cannot set ieee80211be without ieee80211ax"

The issue is seen only when switching within/to DFS channels because
hostapd_switch_channel_fallback() does not set 'ieee80211ax' in
hostapd configuration unless 'he_enabled' is set for the new channel.

Set 'he_enabled' in struct hostapd_freq_params for channel switch
when EHT is enabled.

Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
2024-08-08 22:18:47 +03:00
Aditya Kumar Singh
c6faa89366 AP MLD: Use the cached per STA profile instead of forming a new one
Now that per STA profile is cached already, there is no need to form it
dynamically on every Probe Request frame.

Use the cached one instead.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:58:47 +03:00
Arunpandi Kannan
74db2b7449 AP MLD: Handle Vendor Specific element inheritance in per STA profile
As per IEEE P802.11be/D7.0, 35.3.3.5.1 (Inheritance in the Per-STA
Profile subelement of Basic Multi-Link element), Note 1, if there exists
one or more Vendor Specific elements carried in a Management frame that
includes the Basic Multi-Link element containing a per-STA profile for a
reported STA, and the contents of the Information field for at least one
of the Vendor Specific elements is not the same as that of at least one
Vendor Specific element that applies to the reported STA, then each
Vendor Specific element that applies to the reported STA is included in
its Per-STA Profile subelement.

Handle this.

Signed-off-by: Arunpandi Kannan <quic_arunpand@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:58:32 +03:00
Sriram R
023d70d6ca AP MLD: Add non-inheritance support for per STA profile reporting
There can be an element in the reporting BSS which is not there in the
reported BSS. This element should not be inherited in the per STA
profile. Hence to indicate this, the corresponding per STA profile
should include a Non-Inheritance element in the per STA profile.

Include Non-Inheritance element in the per STA profiles when needed.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:58:08 +03:00
Sriram R
b5359d01ed AP MLD: Intersect per STA profile with the reporting BSS
If an element is present in the reporting BSS and it is also present in
the reported BSS and the contents are same, ideally, the reported BSS
need not carry such element in its per STA profile. Such elements are
assumed to be inherited from the reporting BSS.

Intersect the reported BSS profile with the reporting BSS and avoid such
element inclusion.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:57:42 +03:00
Sriram R
abe990afb9 AP MLD: Ignore elements which are not meant to be included in per STA profile
There are certain elements which should not be included in a per STA
profile.

Ignore such elements.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:57:35 +03:00
Sriram R
2042cae9b3 AP MLD: Generate and keep per STA profiles for each link
Currently, upon receiving a Probe Request frame, per STA profile is
generated and added to the Probe Response frame. However, the per STA
profile remains unchanged unless there’s a property change in one of the
affliated link of the AP MLD. This approach introduces unnecessary delay
in forming and sending out the Probe Response frame.

To optimize this process, generate the per STA profile for each link at
the start and store it. When needed, it can be simply copied into the
Probe Response frame. Additionally, whenever there’s a change in the
link’s properties, re-generate the per STA profiles for all affiliated
links of the AP MLD.

As an initial step, copy the complete per STA profile and store it
within the links. The intersection with reporting BSS and inheritance
will be addressed in a subsequent change. Then finally, this will be
used to generate the Probe Response frame. As of this commit, no change
in adding per STA profiles in the Probe Response frame.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Co-developed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:57:09 +03:00
Sriram R
8f07e9699b Move mld_link_info structure to hostapd.h header file
At present, the mld_link_info structure is nested within the mld_info
structure. However, a future modification will require mld_link_info to
be outside of mld_info. To address this, move the mld_link_info
structure to hostapd.h so that it can be accessed both in the current
context and in the location needed for the upcoming change.

No functional changes.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 18:57:04 +03:00
Amith A
5cb6747f97 Add support to switch channel when CAC is in progress
Prior to initiating communication on a DFS channel, channel availability
check needs to be performed. During this period, the AP does not beacon.
Hence, no channel switch was allowed during this period. However, if a
user wishes to switch to a non-DFS channel during the potentially long
CAC period and start transmission immediately, there is no provision to
do that currently.

Extend the existing CHAN_SWITCH control interface command to allow
channel switch even when the AP is in CAC state. To do this, first
disable the interface to abort the CAC in progress and then configure
the interface with the new parameters and finally re-enable the
interface.

Signed-off-by: Amith A <quic_amitajit@quicinc.com>
2024-08-07 11:37:00 +03:00
Rameshkumar Sundaram
b7f08c28cd WNM: Fix potential NULL pointer dereference during assoc response handling
In the send_assoc_resp() function, there’s a chance that the sta
argument could be NULL. Therefore, it’s crucial not to directly
dereference sta without first checking whether it’s a valid pointer.
However, commit 58ac46baf7 (“WNM: AP configuration to allow BSS max
idle period requests”) introduces direct dereferencing of max idle
period from sta, which might lead to a NULL pointer dereference. Fix
this now.

Fixes: 58ac46baf7 ("WNM: AP configuration to allow BSS max idle period requests")
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-07 11:34:07 +03:00
Karthik M
c7e704bdf9 hostapd: Add Bandwidth Indication subelement support for channel switch
The Bandwidth Indication subelement contains channel bandwidth, channel
center frequency, and optionally punctured subchannels.

As per IEEE P802.11be/D7.0, 35.15.3 (Channel switching methods for an
EHT BSS), if a Channel Switch Announcement element or an Extended
Channel Switch Announcement element is used to announce a switch to an
EHT BSS operating channel width wider than 160 MHz or to an EHT BSS
operating channel width including at least one punctured 20 MHz
subchannel, the Bandwidth Indication subelement in the Channel Switch
Wrapper element shall be present in the same frame.

Hence, add it into the Beacon and Probe Response frames under the above
mentioned conditions.

Signed-off-by: Karthik M <quic_karm@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 23:15:58 +03:00
Karthik M
c9d0c6fd7e hostapd: Refactor Channel Switch Wrapper element generation
The Wide Bandwidth Channel Switch subelement was directly appended in
the Channel Switch Wrapper element function
hostapd_eid_wb_chsw_wrapper(). However, a subsequent change would add
Bandwidth Indication subelement in the Channel Switch Wrapper element.
Hence using the same function name would be confusing.

Hence, refactor the current code into two functions. The first function
hostapd_eid_chsw_wrapper() forms the channel switch wrapper element.
This calls hostapd_eid_wb_channel_switch() to add a Wide Bandwidth
Channel Switch subelement inside it.

No functionality change.

Signed-off-by: Karthik M <quic_karm@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 22:52:19 +03:00
Manish Dharanenthiran
b592c1586e nl80211: Handle nl80211_cqm_event per BSS
During MLO, an nl80211_cqm_event may be received by any BSS. Directing
this event to the first BSS may not be suitable as it might not
correspond to the link the event is meant for. Hence, there is a need to
handle this on per-BSS basis.

Therefore, handle nl80211_cqm_event per BSS. The event handler further
uses the address information present in the event to fetch the intended
link BSS if no matching STA entry was found based on the initial
ap_get_sta() call.

Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 20:17:47 +03:00
Manish Dharanenthiran
89c31feb31 Relocate the declaration of the hostapd_find_by_sta() function to top
The hostapd_find_by_sta() function may be utilized by multiple driver
events. Therefore, it should be declared at the outset to ensure
accessibility by all event handlers.

No functional changes.

Signed-off-by: Manish Dharanenthiran <quic_mdharane@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 20:17:47 +03:00
Aditya Kumar Singh
83c4adcdac hostapd: Add Max Channel Switch Time element support
The Max Channel Switch Time element indicates the time delta between the
time the last beacon is transmitted by the AP in the current channel and
the expected time of the first Beacon frame transmitted by the AP in the
new channel.

IEEE P802.11be/D7.0, 35.3.11 (ML procedures for (extended) channel
switching and channel quieting) indicates that if an AP affiliated with
an AP MLD is switching channel, Max Channel Switch Time element shall be
included in every Beacon and Probe Response frame it transmits.

Add support to include the Max Channel Switch Time element in Beacon and
Probe Response frames during channel switch announcement for an AP
affiliated with an AP MLD.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 18:34:34 +03:00
Aditya Kumar Singh
9f334fe683 Share usec-to/from-TU conversion macros in a general location
These can be used outside the context of FST and hostapd.c, so move the
macro definitions into a shared header file. In addition, fix the
currently unused US_TO_TU() definition and rename "US" to "USEC".

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-06 18:05:18 +03:00
Sidhanta Sahu
69deac87fb AP MLD: Ensure successful addition of link item into list
Currently, hapd->link is added to the MLD links list during driver
initialization and setup BSS operation. However, a call trace has been
observed where a BSS link item is not present in the list and an attempt
is made to delete it from the list. This scenario occurs during the
deinitialization operation, which calls hostapd_bss_link_deinit() and
tries to remove the hapd->link which is not present in the list.

Ensures that the link item is added to the list only after the
successful operation of link addition. Also ensure that mld->num_links
increments only when the addition is successful. Therefore, return from
hostapd_bss_link_deinit(), if mld->num_links is zero. Since the mld
object is shared among all the links, num_links has to be incremented
only when the addition is successful.

Call trace:
        dl_list_del.lto_priv.9.lto_priv ()
        hostapd_bss_link_deinit.lto_priv ()
        hostapd_bss_deinit ()
        hostapd_interface_deinit ()
        hostapd_interface_deinit_free ()
        hostapd_main ()

Signed-off-by: Sidhanta Sahu <quic_sidhanta@quicinc.com>
2024-08-06 00:29:00 +03:00
Veerendranath Jakkam
ca58be3da4 SAE: Add group 20 in default groups when AP started with SAE-EXT-KEY
hostapd used to always enable only the group 19 when SAE groups were not
configured explicitly in hostapd.conf. This may cause undesired
connection delay with STAs which use group 20 as the primary group with
SAE-EXT-KEY AKM during SAE authentication attempt.

To avoid this, enable group 20 in default groups when AP supports
SAE-EXT-KEY and SAE groups have not been configured explicitly in
hostapd.conf.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-06 00:06:22 +03:00
Aditya Kumar Singh
666d695bbd nl80211: Fix simultaneous scanning failure in case of MLO
Currently only one scan can be performed on per phy level at a time in
the driver. Due to this, if another scan request is sent via anoother
underlying phy, the kernel returns -EBUSY. This would result in hostapd
trying to set the interface into station mode if it was originally in AP
mode and retry sending a scan request. However, this behavior is
expected in case of multi link operation and hence there is no need to
switch the mode as such.

Hence, add logic to not change the NL mode if the kernel returns -EBUSY
during multi link AP operation. The caller can accordingly decide and,
if needed, it can re-schedule a scan request after some time.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-05 20:34:12 +03:00
Aditya Kumar Singh
fd55dfe16e nl80211: Fix scan request and its related events handling with MLO
Currently, whenever a scan is started, it uses drv's first BSS only
whether it is AP or STA interface. However, with AP MLD related changes,
the same drv could be used by other BSSs as well which needs scanning.
Hence, the current logic will not work since scan needs to be handled on
a non-first BSS as well.

Move the logic of always using drv's first BSS during scan events to
using BSS on which the event arrived.

Also, for AP MLD operation, even though the BSS is same, the link BSS
also needs to be identified. Hence, add a back pointer in the BSS struct
which would be used to point to the link BSS which requested the scan on
that BSS. This will help in routing the scan events to an appropriate
BSS ctx.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
2024-08-05 20:34:12 +03:00
Gal Savion
23456e480e Avoid sending DEAUTH or DISASSOC packet when using flag tx=0
hostapd would send DISASSOC packet (after quiet DEAUTH) or DEAUTH packet
(after quiet DISASSOC) to the station after some inactivity timeout,
even though the command has tx=0 parameter. Fix this so that tx=0 cleans
the STA info without sending any DISASSOC or DEAUTH packets.

Signed-off-by: Gal Savion <gsavion@maxlinear.com>
2024-08-03 20:25:20 +03:00
Benjamin Berg
619ff3d2e8 build: Add simple compile_commands.json generation
This can be used with a clangd server to get code completion and cross
references in editor. To simplify the generation, create .cmd files for
most object files while building that contains the base directory and
command that was used when compiling it.

A very simple gen_compile_commands.py is provided which will read one or
more build directories and generate the compile_commands.json file for
it.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-03 20:16:18 +03:00
Jouni Malinen
733069fd4c tests: Use newer hostapd.add_ap() argument style
Convert the easy cases of old hostapd.add_ap() uses to the new one.

Signed-off-by: Jouni Malinen <j@w1.fi>
2024-08-03 19:02:29 +03:00
Janusz Dziedzic
222d443950 tests: Use remote_cli in remote testing
This allows to use remote wpa_cli/hostapd_cli for:
 - hwsim wrapper
 - example test case

For example,
 modprobe mac80211_hwsim radios=8
 ./run-tests.py -d hwsim0 -d hwsim1 -d hwsim2 -r hwsim3 -r hwsim4 -h ap_wpa2_psk -v

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
2024-08-03 18:35:10 +03:00
Janusz Dziedzic
205dbb0fef tests: Allow user name to be skipped in ssh connection with remotehost
Allow to skip user name when we run ssh user@hostname.

We can specify user name in .ssh/config and simplify using network name
spaces mapped per user.

An example .ssh/config:

 Host localhost
    HostName localhost
    User root

 Host test1
    HostName testpc
    User wlan1

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
2024-08-03 18:35:10 +03:00
Janusz Dziedzic
9ff4fd30ff tests: Allow to use remote hostapd_cli in Hostapd classes
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
2024-08-03 18:35:10 +03:00
Janusz Dziedzic
871bfdcdf6 tests: Allow to use remote wpa_cli in WpaSupplicant class
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
2024-08-03 18:35:02 +03:00
Janusz Dziedzic
d3f340c869 tests: Add RemoteCtrl class
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
2024-08-03 18:17:37 +03:00
Matthew Wang
d42cfaa397 Move wpas_trigger_6ghz_scan() up in the file
This avoids an unnecessary forward declaration for the static function.

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
2024-08-03 12:27:39 +03:00
Matthew Wang
a66cb09930 Trigger a 6 GHz scan if RNR contains matching short SSID
If a scan triggers a regdom update into a 6 GHz-allowed regdom, and an
RNR element in one of the legacy band scan results points to a 6 GHz
scan result with a short SSID matching the current_ssid, delay
connection in favor of a 6 GHz-only scan. This will optimize the case in
which we first connect to a 5 GHz AP, then later roam to a 6 GHz one by
directly connecting to the 6 GHz one.

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
2024-08-03 12:25:47 +03:00
Matthew Wang
acd9332c3b Fix success check for triggering 6 GHz scan
wpas_trigger_6ghz_scan() returns 1 on success and 0 on failure to
trigger the scan. Checking the return value to be less than zero is not
correct. This was supposed to check for success, i.e., greater than
zero.

Fixes: 42add3c27b ("Scan 6 GHz channels after change to 6 GHz-allowed regdom")
Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
2024-08-03 12:17:10 +03:00
Jintao Lin
d40788a5cb P2P: Use specified frequency for group client in P2P_GROUP_ADD command
In P2P_GROUP_ADD command and GroupAdd dbus method, frequency is passed
in as a parameter when restarting a persistent group. This is the group
operating frequency determined out of band. Use this pre-determined
frequency in P2P client as well to expedite the P2P scan.

Signed-off-by: Jintao Lin <jintaolin@chromium.org>
2024-08-03 11:49:24 +03:00
Ruth Mekonnen
9c0a6d64d0 dbus: Emit ScanInProgress6GHz property
Expose whether a 6 GHz scan is in progress with the ScanInProgress6GHz
property and flush properties as soon as the property is updated, so
that platforms can choose not to disconnect while a 6 GHz scan is in
progress. Once the 6 GHz scan has completed and scan results have been
received, the ScanInProgress6GHz property is reset to false.

Signed-off-by: Ruth Mekonnen <rmekonnen@chromium.org>
2024-08-03 11:43:57 +03:00
Ruth Mekonnen
b53d7a6a86 Add non-PSC channels to 6 GHz scan request
When non_coloc_6ghz = false, the STA is expected to scan for colocated
APs. However, if the colocated AP is on a non-PSC channel, it will not
be detected during the 6 GHz-only scan because the frequency list is
limited to PSC channels. Even when the NL80211_SCAN_FLAG_COLOCATED_6GHZ
is set, the cfg80211 only scans a subset of the channels in the original
6 GHz scan request. Therefore, this patch adds non-PSC channels to the
original 6 GHz scan request.

Signed-off-by: Ruth Mekonnen <rmekonnen@chromium.org>
2024-08-03 11:36:35 +03:00
Benjamin Berg
9e50c12b31 WNM: Scan for BSSID if there are forbidden neighbors
The test to scan for a single BSSID assumed that there is only a single
neighbor in the candidate list. Also do this optimization if there are
multiple neighbors but only one of them is valid.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:49:32 +03:00
Benjamin Berg
3cf4b4ad88 tests: Add a WNM tests to check candidate list is used if not required
This tests that the candidate list is used even if it is not required
because the abridged and preferred candidate list included bits are not
set.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:49:32 +03:00
Benjamin Berg
54b25b7c1d WNM: Always parse candidate list
The preferred candidate list included bit just makes parsing the list
mandatory. The AP may still include a candidate list which we should use
to be able to optimize scanning. As such, always parse out the list but
still verify that if the list is not empty if the bit is set.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:49:19 +03:00
Benjamin Berg
d9d8627873 WNM: Consolidate the scanning paths for BTM requests
There was an ancient code path to trigger a scan that was apparently
forgotten when the code was extended over time. It does not make any
sense to trigger a scan twice, so remove the earlier scan.

The earlier scan call was avoiding to trigger a new scan if a fixed
BSSID is configured. This seems like a reasonable restriction to do, so
add this check before starting a scan.

Consolidate everything so that scanning happens at the end of the
functions unless we bail out before. Add a "reset" label for all other
cases to ensure that we don't leave things in the a bad state.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:40:37 +03:00
Benjamin Berg
3b6abe3580 WNM: Reject requests with an invalid dialog token
The dialog token must be non-zero. We are using this fact internally to
track the state in some cases, so ensure that the assumption is valid.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:22:34 +03:00
Avraham Stern
f4a9cb96d6 MBO: Always accept BTM request with disassociation imminent bit set
According to Multiband Operation specification (r17, section 3.5.2),
a BSS Transition Management Request with the disassociation imminent
bit set should always be accepted.

This is enforced in case the request did not include a candidate list.
However, in case a candidate list was included but none of the APs in
the candidate list was found in the scan results, the request is
rejected.

Fix that by always accepting a request with the disassociation imminent
bit set even if no roaming candidate was found.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:20:53 +03:00
Benjamin Berg
020f20a222 tests: Set the abridged bit in BTM tests
Many of the WNM tests assume that the supplicant will only select a
neighbor that was included in the candidate list. However, without the
abridged bit being set, the supplicant is allowed to also select any BSS
that is not explicitly included in the list.

Prepare for the supplicant handling the abridged bit by setting it in
the tests where relevant.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:16:10 +03:00
Benjamin Berg
adc6ca34a0 WNM: Move neighbor report test into wnm_is_bss_excluded()
Having it in wnm_is_bss_excluded() is more generic as it works for other
locations (e.g., MLD link selection). So move the test and add a check
for the abridged bit while at it. Note that without the abridged bit
check another check would be needed (e.g., checking wnm_dialog_token) to
ensure that there isn't a rejection unless a BTM is in progress.

compare_scan_neighbor_results() calls wpa_scan_res_match() which calls
wnm_is_bss_excluded() so the previous behavior is maintained for WNM
scan result processing.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 13:06:59 +03:00
Benjamin Berg
a832312806 WNM: Swap logic in wnm_is_bss_excluded() to allow more checks
Following commits will move more checks into wnm_is_bss_excluded().
Prepare for that by changing the logical flow so that further checks can
be inserted.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:58:27 +03:00
Benjamin Berg
582b5eff40 WNM: Remove unused age parameter for neighbor comparison
compare_scan_neighbor_results() was taking an age parameter to check
whether the BSS has been seen recently. This was used historically in a
codepath when no new scan was done. However, the logic was changed in
commit 20ed289a78 ("WNM: Clean up old scan data processing") and the
parameter is not used at all anymore as it is replaced by a different
logic. Remove it.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:57:34 +03:00
Benjamin Berg
4bbe004e06 WNM: Split candidate list parsing into a separate function
ieee802_11_rx_bss_trans_mgmt_req() is already dealing with a lot of
things including the decisions on how to act on the frame. Split out
candidate list parsing to make it easier to work with the function.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:53:07 +03:00
Benjamin Berg
b791d1f342 WNM: Use os_relatime_add_ms() helper
Just simplify the code a little bit by using the helper instead of doing
the math inline.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:48:42 +03:00
Jouni Malinen
da1a86afc6 WNM: Rename wnm_dissoc_timer
Use "disassoc" instead of "dissoc" when referring to disassociation.

Signed-off-by: Jouni Malinen <j@w1.fi>
2024-08-02 12:48:25 +03:00
Benjamin Berg
ebd18f1ade WNM: Rename wnm_dissoc_addr
Use "disassoc" instead of "dissoc" when referring to disassociation.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:48:25 +03:00
Benjamin Berg
93eb3b83c6 WNM: Store whether disassociation address is an MLD MAC address
Commit 17a2aa822c ("WNM: Follow BTM procedure if the last link is
dropped") added code to store either the MLD MAC address or BSSID when
being disassociated. However, it did not save which one was stored
making the tests later on awkward.

Store whether it was an MLD MAC address or not and then do the test
accordingly.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:48:25 +03:00
Benjamin Berg
63ac001ed2 WNM: Only trigger selection logic for own scans
Commit e508c070c4 ("WNM: Keep BTM information until connection
completes") changed the logic so that much of the information about a
transition management request will be kept around for longer. However,
doing this also implies that the scan logic can be called multiple times
with wnm_dialog_token being set.

Add a guard to bail out if the scan was not done for a BTM request. But,
add it after the transition candidate validity check so that we reset
the state when a new scan invalidated it.

However, invalidation does not make sense for any scan, primarily an ML
probe request during a connection attempt should not trigger
invalidation. So move the call to wnm_scan_process() further down in the
list to avoid issues.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
2024-08-02 12:48:18 +03:00
Purushottam Kushwaha
bb96540ef5 Add QCA vendor attribute to skip recently scanned channels
Add a new vendor attribute
QCA_WLAN_VENDOR_ATTR_SCAN_SKIP_CHANNEL_RECENCY_PERIOD for sub command
QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN to skip the recently scanned
channels within specified time (in ms), thus reducing the number of
channels for requested scan.

Signed-off-by: Purushottam Kushwaha <quic_pkushwah@quicinc.com>
2024-08-01 20:16:50 +03:00
Veerendranath Jakkam
bc43e75b2b MLD STA: Fix destination address for EAPOL frames
For MLO association, specify the destination address as the AP MLD MAC
address for sending EAPOL frames. Previously, this was set to the BSSID
in all cases (and hoped for the driver to map it to MLD MAC address when
needed).

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-08-01 20:15:07 +03:00
David Bauer
69d18ab9f2 bgscan: Add OWE transition mode SSID to network scan
Add transition mode SSIDs to the SSID scan-list for bgscan. This is
currently missing and bgscan fails to scan for SSIDs on the OWE
transition network if one is currently used.

Signed-off-by: David Bauer <mail@david-bauer.net>
2024-08-01 18:16:34 +03:00
David Bauer
56e8f8bf34 OWE: Enable roaming between OWE APs
This allows to use the ROAM control interface command to force roaming
on a transition network. Previously, this was not possible, as the open
SSID is stored for the connection profile. Add a new function to also
return OWE transition networks if the profile SSID is set as the
transition-ssid for the OWE RSN network.

Signed-off-by: David Bauer <mail@david-bauer.net>
2024-08-01 18:06:54 +03:00
David Bauer
ddfed3f084 OWE: Reduce code duplication in OWE element parsing
Reduce the code-duplication for methods handling the OWE transition
mode.

Signed-off-by: David Bauer <mail@david-bauer.net>
2024-08-01 18:01:07 +03:00
Johannes Berg
1e54160515 hostapd: Fix BSS parameters change count on link removal
The value currently is simply incremented, but it must not
reach 255 and rather wrap around from 254 to 0, since in
the Reduced Neighbor Report 255 means unknown. Fix that.

Fixes: d95838b793 ("AP: Add support for testing ML link removal")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-08-01 17:30:12 +03:00
Diya Sati
21c3a7494c Add Link ID attribute for external ACS vendor command
The Link Id attribute is required for
qca_wlan_vendor_attr_external_acs_event to identify the link on which
the command is received for an AP MLD.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-01 10:38:24 +03:00
Shiva Sankar Gajula
5942965955 Add link ID attribute to ADD_STA_NODE QCA vendor command for AP MLD
Add QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_LINKID attribute to the
ADD_STA_NODE command to identify a specific link affiliated to an AP
MLD.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-08-01 10:37:10 +03:00
Purushottam Kushwaha
e1ab680c98 Add QCA vendor subcommand to request audio transport switch
Add a new sub command QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH
to request the audio data transport switch in both the command and event
path. This is used when two or more audio data transports are available
between peers.

Signed-off-by: Purushottam Kushwaha <quic_pkushwah@quicinc.com>
2024-08-01 10:32:00 +03:00
Vinay Gannevaram
7e0e69cfea SAE: Send external auth status after sending Authentication frame
The driver might delete the STA node details on receiving external auth
status. In SAE authentication failure case on the AP, an Authentication
frame with a failure status is sent to the driver after sending the
external auth status. Authentication frame transmission didn't have a
dependency with STA node details earlier, but with MLO, Authentication
frames should be transmitted using the link address for a given MLD MAC
address by the supplicant. Since MLD to link address translation is done
by the driver, the STA node details are required to transmit the
Authentication frame. Hence, send external auth status to the driver
after sending the Authentication frame.

SAE external auth was introduced in commit 4ffb0fefe4 ("hostapd:
Support external authentication offload in AP mode"), which requires the
change in order of sending Authentication frame and auth status in case
of failure when using MLO.

Signed-off-by: Vinay Gannevaram <quic_vganneva@quicinc.com>
2024-07-31 18:28:39 +03:00
Jouni Malinen
be6e4279fa RSNO: Verify all RSNE/RSNXE variants in multi-link cases
Use the RSN Override Link KDE to include the override variants of the
RSNE/RSNXE for each link so that all variants are verifies when
processing the protected EAPOL-Key message 3/4.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 19:56:00 +03:00
Jouni Malinen
4d110b4f87 tests: More detailed error logging for RSN overriding with MLD
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 18:52:15 +03:00
Jouni Malinen
521374b978 RSNO: Include all RSNE/RSNXE variants in EAPOL-Key message 3/4
This allows all variants to be verified based on a protected frame to
achieve robust downgrade protection.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 18:52:15 +03:00
Jouni Malinen
6f522baa1b RSNO: Use SNonce cookie to indicate support for RSN overriding
This provides an implicitly protected (SNonce is used as an input to PTK
derivation) mechanism for a STA to indicate support for RSN overriding
in a manner that does not cause interopability issues with deployed APs.

In addition, update sm->SNonce on the Authenticator only based on
message 2/4 since that is the only EAPOL-Key message that is defined to
provide the actual SNonce value. While clearing of this internal buffer
on message 4/4 might not cause issues, it is better to keep the actual
SNonce value here since the SNonce cookie can be used at a later point
in the sequence.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 12:16:05 +03:00
Jouni Malinen
62ca121f96 RSNO: Use the RSN Selection element to indicate which variant was used
This replaces the use of the RSNE Override and RSNE Override 2 elements
with empty payload to indicate which RSNE variant was used.

In addition, this adds stricter validation of the RSNE in
(Re)Association Request frame to allow only the pairwise cipher suites
and AKMs listed in the indicated RSNE variant to be used.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 12:16:05 +03:00
Jouni Malinen
524c452153 RSNO: Remove unused override element generation
The separate RSNOE/RSNO2E/RSNXOE buffers were not actually used on the
Authenticator, so remove them.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-30 12:16:05 +03:00
Chenming Huang
13648dde91 FILS: Check for potential NULL return
hostapd_eid_assoc_fils_session() might return NULL if memory allocation
fails. This NULL value then will be used for invalid calculation and
cause unspecified behavior or be dereferenced unexpectedly. Avoid this
with an explicit check of the returned pointer.

Signed-off-by: Chenming Huang <quic_chenhuan@quicinc.com>
2024-07-25 21:03:59 +00:00
Adil Saeed Musthafa
376adfea8d RSNO: Protect wpa_ie_buf3 from reuse explicitly
Use else-if check for better clarity regarding usage of wpa_ie_buf3 to
make it explicit that memory is allocated for this pointer only once.

Signed-off-by: Adil Saeed Musthafa <quic_adilm@quicinc.com>
2024-07-25 21:03:51 +00:00
Jouni Malinen
4adf234cd3 RSNO: Remove override elements from EAPOL-Key msg 3/4
This was not done in case the STA did not use RSN overriding.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-25 19:22:00 +00:00
Jouni Malinen
9732c8b85c wlantest: Remove unused QoS handling from GCMP nonce generation
This was copied from CCMP, but is not needed (and can trigger compiler
warnings) with GCMP.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-25 00:39:30 +00:00
Jouni Malinen
e0053bf9d0 tests: Long extra KDE in EAPOL-Key msg 3/4
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-24 20:35:11 +00:00
Jouni Malinen
296104d35c Testing functionality to allow EAPOL-Key Reserved field to be set
The new hostapd configuration parameter eapol_key_reserved_random=1 can
be used for testing STA/Supplicant functionality to accept a random
value in the Reserved field within EAPOL-Key frames.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-24 17:22:42 +00:00
Jouni Malinen
2e4c612dd2 Allow RSNE/RSNXE/RSNOE/RSNO2E/RSNXOE to be replace for testing
This is convenient for testing STA behavior with various RSN element
combinations and special cases.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-24 01:01:29 +00:00
Jouni Malinen
bb61f6cb95 RSNO: Support over two octets of RSNXOE capabilities
The RSNXE generation function was extended to support this earlier, but
that update was missed from the RSNXOE variant.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-23 21:36:46 +00:00
Jouni Malinen
8b2ddfdbb6 RSNO: Allow RSNXE to be omitted
Add an explicit rsn_override_omit_rsnxe=1 configuration parameter to
allow the RSNXE to be omitted when using the RSNXOE and wanting to
minimize interoperability issues with STAs that might recognize the
RSNXE, but not handle it correctly, e.g., when multiple octets of
payload is included.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-23 21:20:45 +00:00
Hu Wang
92374d59d4 Enhance select_network() to trigger new scans in some cases
wpa_supplicant select_network() relies on fast_associate to reuse old
scan results. However, this approach does not apply in some cases in
Android:

1 - If the selected network is hidden, and the SSID is in Chinese,
Android switches between fallback SSIDs, necessitating a new scan for
switching between different hidden SSIDs.

2 - Similarly, if the selected SSID is OWE (Opportunistic Wireless
Encryption), and the OWE SSID bands have been changed, select_network()
requires a fresh scan to discover hidden OWE SSIDs.

To address these, enhance select_network() to trigger new scans instead
of relying on fast_associate. This improves network selection behavior
in Android.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-22 19:01:18 +00:00
Veerendranath Jakkam
ff99012d84 RSNO: Use correct MLO capability while fetching RSNE/RSNXE
Use current connection MLO capability to fetch the appropriate
RSNE/RSNXE variant while processing association event.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-07-22 18:50:24 +00:00
Veerendranath Jakkam
526ea193c8 Fallback to RSNXE when AP is not using valid RSN Overrding
wpa_supplicant was ignoring RSNXE also if the AP is not using valid
RSN overriding combination when the STA supports RSN overriding. Fix
this fallback to the RSNXE when AP is not using valid RSN overriding.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-07-22 18:48:20 +00:00
Vinay Gannevaram
4417b5ba86 Add QCA vendor interface to support Unsynchronized Service Discovery
Add a new QCA command QCA_NL80211_VENDOR_SUBCMD_USD and related
attributes to support Unsynchronized Service Discovery (USD).

Device in active subscriber role sends SDF frames with service
information to find devices that advertise or publish the required
services. Device address, operation type, instance id, service_id,
channel info, service specific info, element container attribute, and
timeout are sent to the driver to initiate USD publish or USD subscribe
operation. The driver sends QCA_NL80211_VENDOR_SUBCMD_USD event with
instance_id and the USD operation status. QCA_NL80211_VENDOR_SUBCMD_USD
is also used to update publish operation and to cancel the publish or
subscribe operation for a service. It also allows all the operations to
be terminated using the USD flush command.

Signed-off-by: Vinay Gannevaram <quic_vganneva@quicinc.com>
2024-07-20 21:00:21 +00:00
Jouni Malinen
8d54863550 tests: RSNE/RSNXE overriding
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
765c48d5ad RSNE/RSNXE overriding for STA
Add support for RSNE/RSNXE Override elements. Use these elements to
determine AP's extended RSN parameters.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
d0b55eb360 Make driver capabilities for AKM suites available within wpa_supplicant
In addition, add some of the previously missed AKM suites from the
default capabilities.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
5488e120d3 Use helper functions to access RSNE/RSNXE from BSS entries
This is a step towards allowing the contents of RSNE/RSNXE to be
overridden.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Veerendranath Jakkam
341bcb2b5c nl80211: Add a capability flag for RSN overriding
Add a new capability flag based on the nl80211 feature advertisement for
RSN overriding support.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-07-20 21:28:28 +03:00
Veerendranath Jakkam
6fad7224be Add QCA vendor feature flags to indicate RSN override elements support
Add a separate feature flag for STA mode to indicate support for RSN
override elements.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
157b016383 RSNE/RSNXE overriding for AP
Allow hostapd to be configured to advertised two separate sets of
RSNE/RSNXE parameters so that RSNE/RSNXE can use a reduced set of
capabilities (e.g., WPA2-Personal only) for supporting deployed STAs
that have issues with transition modes while the new override elements
can use a newer security option (e.g., WPA3-Personal only) for STAs that
support the new mechanism.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
b8a2d11ae0 Allow RSNXE Override element to override RSNXE contents during parsing
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
48ca68f6f8 Allow RSNE Override element to override RSNE contents during parsing
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
c16ac89be2 Add RSN overriding elements into IE parsing
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
6b0ce29d25 Define WFA vendor specific element types for RSNE/RSNXE overriding
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
2024-07-20 21:28:28 +03:00
Jouni Malinen
e99cdfae41 The main branch is now used for v2.12 development
Signed-off-by: Jouni Malinen <j@w1.fi>
2024-07-20 21:16:55 +03:00
145 changed files with 8873 additions and 3898 deletions

3
.gitignore vendored
View file

@ -6,3 +6,6 @@ wpaspy/build
**/parallel-vm.log
tags
build/
# clangd commands and cache
compile_commands.json
.cache

View file

@ -883,6 +883,11 @@ fi.w1.wpa_supplicant1.CreateInterface.
<p>The most recent roam success or failure.</p>
</li>
<li>
<h3>ScanInProgress6GHz - b - (read)</h3>
<p>Whether a 6GHz scan is currently in progress.</p>
</li>
<li>
<h3>SessionLength - u - (read)</h3>
<p>The most recent BSS session length in milliseconds.</p>

54
gen_compile_commands.py Executable file
View file

@ -0,0 +1,54 @@
#!/usr/bin/env python3
# compile_commands.json generator
# Copyright (C) 2024 Intel Corporation
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import os
import sys
import glob
import json
import argparse
parser = argparse.ArgumentParser(description='Read each of the build directories that are given and generate '
'a compile_commands.json file. If a source file is found multiple times, '
'then the compile flags from the last build directory will be used.')
parser.add_argument('-o', '--output', default='compile_commands.json', type=str,
help="Output file to generate")
parser.add_argument('builddirs', nargs='+', type=str, metavar="builddir",
help='Build directories to search')
args = parser.parse_args()
files = {}
for builddir in args.builddirs:
for cmd_file in glob.glob('**/*.o.cmd', root_dir=builddir, recursive=True):
with open(os.path.join(builddir, cmd_file), encoding='ascii') as f:
base_dir, cmd = f.readline().split(':', 1)
src_file = cmd.rsplit(maxsplit=1)[1]
src_file = os.path.abspath(os.path.join(base_dir, src_file))
files[src_file] = {
'command': cmd.strip(),
'directory': base_dir,
'file': src_file,
}
flist = json.dumps(sorted(list(files.values()), key=lambda k: k['file']), indent=2, sort_keys=True)
try:
# Avoid writing the file if it did not change, first read original
with open(args.output, 'rt', encoding='UTF-8') as f:
orig = []
while data := f.read():
orig.append(data)
orig = ''.join(orig)
except OSError:
orig = ''
# And only write if something changed
if orig != flist:
with open(args.output, 'wt', encoding='UTF-8') as f:
f.write(flist)

View file

@ -166,12 +166,6 @@ OBJS += ../src/common/hw_features_common.o
OBJS += ../src/eapol_auth/eapol_auth_sm.o
ifdef CONFIG_UBUS
CFLAGS += -DUBUS_SUPPORT
OBJS += ../src/utils/uloop.o
OBJS += ../src/ap/ubus.o
LIBS += -lubox -lubus
endif
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage -U_FORTIFY_SOURCE

View file

@ -2436,6 +2436,31 @@ static int get_u16(const char *pos, int line, u16 *ret_val)
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS
static bool get_hexstream(const char *val, struct wpabuf **var,
const char *name, int line)
{
struct wpabuf *tmp;
size_t len = os_strlen(val) / 2;
tmp = wpabuf_alloc(len);
if (!tmp)
return false;
if (hexstr2bin(val, wpabuf_put(tmp, len), len)) {
wpabuf_free(tmp);
wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
line, name, val);
return false;
}
wpabuf_free(*var);
*var = tmp;
return true;
}
#endif /* CONFIG_TESTING_OPTIONS */
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@ -3156,6 +3181,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa_key_mgmt = hostapd_config_parse_key_mgmt(line, pos);
if (bss->wpa_key_mgmt == -1)
return 1;
} else if (os_strcmp(buf, "rsn_override_key_mgmt") == 0) {
bss->rsn_override_key_mgmt =
hostapd_config_parse_key_mgmt(line, pos);
if (bss->rsn_override_key_mgmt == -1)
return 1;
} else if (os_strcmp(buf, "rsn_override_key_mgmt_2") == 0) {
bss->rsn_override_key_mgmt_2 =
hostapd_config_parse_key_mgmt(line, pos);
if (bss->rsn_override_key_mgmt_2 == -1)
return 1;
} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
bss->wpa_psk_radius = atoi(pos);
if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@ -3187,6 +3222,32 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
} else if (os_strcmp(buf, "rsn_override_pairwise") == 0) {
bss->rsn_override_pairwise =
hostapd_config_parse_cipher(line, pos);
if (bss->rsn_override_pairwise == -1 ||
bss->rsn_override_pairwise == 0)
return 1;
if (bss->rsn_override_pairwise &
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
wpa_printf(MSG_ERROR,
"Line %d: unsupported pairwise cipher suite '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "rsn_override_pairwise_2") == 0) {
bss->rsn_override_pairwise_2 =
hostapd_config_parse_cipher(line, pos);
if (bss->rsn_override_pairwise_2 == -1 ||
bss->rsn_override_pairwise_2 == 0)
return 1;
if (bss->rsn_override_pairwise_2 &
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
wpa_printf(MSG_ERROR,
"Line %d: unsupported pairwise cipher suite '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "group_cipher") == 0) {
bss->group_cipher = hostapd_config_parse_cipher(line, pos);
if (bss->group_cipher == -1 || bss->group_cipher == 0)
@ -3208,6 +3269,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->rsn_preauth_interfaces);
bss->rsn_preauth_interfaces = os_strdup(pos);
#endif /* CONFIG_RSN_PREAUTH */
} else if (os_strcmp(buf, "rsn_override_omit_rsnxe") == 0) {
bss->rsn_override_omit_rsnxe = atoi(pos);
} else if (os_strcmp(buf, "peerkey") == 0) {
wpa_printf(MSG_INFO,
"Line %d: Obsolete peerkey parameter ignored", line);
@ -3642,6 +3705,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->use_driver_iface_addr = atoi(pos);
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "rsn_override_mfp") == 0) {
bss->rsn_override_mfp = atoi(pos);
} else if (os_strcmp(buf, "rsn_override_mfp_2") == 0) {
bss->rsn_override_mfp_2 = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
if (os_strcmp(pos, "AES-128-CMAC") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
@ -4462,23 +4529,29 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->radio_measurements[0] |=
WLAN_RRM_CAPS_NEIGHBOR_REPORT;
} else if (os_strcmp(buf, "own_ie_override") == 0) {
struct wpabuf *tmp;
size_t len = os_strlen(pos) / 2;
tmp = wpabuf_alloc(len);
if (!tmp)
if (!get_hexstream(pos, &bss->own_ie_override,
"own_ie_override", line))
return 1;
if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
wpabuf_free(tmp);
wpa_printf(MSG_ERROR,
"Line %d: Invalid own_ie_override '%s'",
line, pos);
} else if (os_strcmp(buf, "rsne_override") == 0) {
if (!get_hexstream(pos, &bss->rsne_override,
"rsne_override", line))
return 1;
} else if (os_strcmp(buf, "rsnoe_override") == 0) {
if (!get_hexstream(pos, &bss->rsnoe_override,
"rsnoe_override", line))
return 1;
} else if (os_strcmp(buf, "rsno2e_override") == 0) {
if (!get_hexstream(pos, &bss->rsno2e_override,
"rsno2e_override", line))
return 1;
} else if (os_strcmp(buf, "rsnxe_override") == 0) {
if (!get_hexstream(pos, &bss->rsnxe_override,
"rsnxe_override", line))
return 1;
} else if (os_strcmp(buf, "rsnxoe_override") == 0) {
if (!get_hexstream(pos, &bss->rsnxoe_override,
"rsnxoe_override", line))
return 1;
}
wpabuf_free(bss->own_ie_override);
bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_status") == 0) {
@ -4540,6 +4613,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
} else if (os_strcmp(buf, "eapol_m3_no_encrypt") == 0) {
bss->eapol_m3_no_encrypt = atoi(pos);
} else if (os_strcmp(buf, "eapol_key_reserved_random") == 0) {
bss->eapol_key_reserved_random = atoi(pos);
} else if (os_strcmp(buf, "test_assoc_comeback_type") == 0) {
bss->test_assoc_comeback_type = atoi(pos);
} else if (os_strcmp(buf, "presp_elements") == 0) {

View file

@ -2454,6 +2454,31 @@ static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
#ifdef NEED_AP_MLME
static bool
hostapd_ctrl_is_freq_in_cmode(struct hostapd_hw_modes *mode,
struct hostapd_multi_hw_info *current_hw_info,
int freq)
{
struct hostapd_channel_data *chan;
int i;
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (!chan_in_current_hw_info(current_hw_info, chan))
continue;
if (chan->freq == freq)
return true;
}
return false;
}
static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
u16 punct_bitmap)
{
@ -2668,6 +2693,15 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
settings.link_id = iface->bss[0]->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
if (iface->num_hw_features > 1 &&
!hostapd_ctrl_is_freq_in_cmode(iface->current_mode,
iface->current_hw_info,
settings.freq_params.freq)) {
wpa_printf(MSG_INFO,
"chanswitch: Invalid frequency settings provided for multi band phy");
return -1;
}
ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
settings.punct_bitmap);
if (ret) {
@ -2735,6 +2769,12 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
return 0;
}
if (iface->cac_started) {
wpa_printf(MSG_DEBUG,
"CAC is in progress - switching channel without CSA");
return hostapd_force_channel_switch(iface, settings);
}
for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT, HE, and EHT config */
@ -3705,6 +3745,7 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
struct wpabuf *ssi = NULL;
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
bool p2p = false;
os_memset(&params, 0, sizeof(params));
/* USD shall use both solicited and unsolicited transmissions */
@ -3738,6 +3779,11 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
continue;
}
if (os_strcmp(token, "p2p=1") == 0) {
p2p = true;
continue;
}
if (os_strcmp(token, "solicited=0") == 0) {
params.solicited = false;
continue;
@ -3759,7 +3805,7 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
}
publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type,
ssi, &params);
ssi, &params, p2p);
if (publish_id > 0)
ret = os_snprintf(buf, buflen, "%d", publish_id);
fail:
@ -3842,6 +3888,7 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
struct wpabuf *ssi = NULL;
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
bool p2p = false;
os_memset(&params, 0, sizeof(params));
@ -3875,6 +3922,11 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
continue;
}
if (os_strcmp(token, "p2p=1") == 0) {
p2p = true;
continue;
}
wpa_printf(MSG_INFO,
"CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
token);
@ -3883,7 +3935,7 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name,
srv_proto_type, ssi,
&params);
&params, p2p);
if (subscribe_id > 0)
ret = os_snprintf(buf, buflen, "%d", subscribe_id);
fail:
@ -4682,23 +4734,360 @@ done:
}
#ifdef CONFIG_IEEE80211BE
#ifndef CONFIG_CTRL_IFACE_UDP
static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld,
char *buf, char *reply,
size_t reply_size,
struct sockaddr_storage *from,
socklen_t fromlen)
{
struct hostapd_data *link_hapd, *link_itr;
int reply_len = -1, link_id = -1;
char *cmd;
bool found = false;
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
cmd = buf;
/* Check whether the link ID is provided in the command */
if (os_strncmp(cmd, "LINKID ", 7) == 0) {
cmd += 7;
link_id = atoi(cmd);
if (link_id < 0 || link_id >= 15) {
os_memcpy(reply, "INVALID LINK ID\n", 16);
reply_len = 16;
goto out;
}
cmd = os_strchr(cmd, ' ');
if (!cmd)
goto out;
cmd++;
}
if (link_id >= 0) {
link_hapd = mld->fbss;
if (!link_hapd) {
os_memcpy(reply, "NO LINKS ACTIVE\n", 16);
reply_len = 16;
goto out;
}
for_each_mld_link(link_itr, link_hapd) {
if (link_itr->mld_link_id == link_id) {
found = true;
break;
}
}
if (!found)
goto out;
link_hapd = link_itr;
} else {
link_hapd = mld->fbss;
}
if (os_strcmp(cmd, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
} else if (os_strcmp(cmd, "ATTACH") == 0) {
if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, NULL))
reply_len = -1;
} else if (os_strncmp(cmd, "ATTACH ", 7) == 0) {
if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, cmd + 7))
reply_len = -1;
} else if (os_strcmp(cmd, "DETACH") == 0) {
if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen))
reply_len = -1;
} else {
if (link_id == -1)
wpa_printf(MSG_DEBUG,
"Link ID not provided, using the first link BSS (if available)");
if (!link_hapd)
reply_len = -1;
else
reply_len =
hostapd_ctrl_iface_receive_process(
link_hapd, cmd, reply, reply_size,
from, fromlen);
}
out:
if (reply_len < 0) {
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
return reply_len;
}
static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct hostapd_mld *mld = eloop_ctx;
char buf[4096];
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply, *pos = buf;
const size_t reply_size = 4096;
int reply_len;
int level = MSG_DEBUG;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s",
strerror(errno));
return;
}
buf[res] = '\0';
reply = os_malloc(reply_size);
if (!reply) {
if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
fromlen) < 0) {
wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
strerror(errno));
}
return;
}
if (os_strcmp(pos, "PING") == 0)
level = MSG_EXCESSIVE;
wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res);
reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos,
reply, reply_size,
&from, fromlen);
if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen) < 0) {
wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
strerror(errno));
}
os_free(reply);
}
static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld)
{
size_t len;
char *buf;
int ret;
if (!mld->ctrl_interface)
return NULL;
len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2;
buf = os_malloc(len);
if (!buf)
return NULL;
ret = os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name);
if (os_snprintf_error(len, ret)) {
os_free(buf);
return NULL;
}
return buf;
}
#endif /* !CONFIG_CTRL_IFACE_UDP */
int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld)
{
#ifndef CONFIG_CTRL_IFACE_UDP
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
if (!mld)
return -1;
if (mld->ctrl_sock > -1) {
wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!",
mld->name);
return 0;
}
dl_list_init(&mld->ctrl_dst);
if (!mld->ctrl_interface)
return 0;
if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
if (errno == EEXIST) {
wpa_printf(MSG_DEBUG,
"Using existing control interface directory.");
} else {
wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
}
if (os_strlen(mld->ctrl_interface) + 1 + os_strlen(mld->name) >=
sizeof(addr.sun_path))
goto fail;
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
os_memset(&addr, 0, sizeof(addr));
#ifdef __FreeBSD__
addr.sun_len = sizeof(addr);
#endif /* __FreeBSD__ */
addr.sun_family = AF_UNIX;
fname = hostapd_mld_ctrl_iface_path(mld);
if (!fname)
goto fail;
os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
strerror(errno));
if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not allow connections - assuming it was left over from forced program termination");
if (unlink(fname) < 0) {
wpa_printf(MSG_ERROR,
"Could not unlink existing ctrl_iface socket '%s': %s",
fname, strerror(errno));
goto fail;
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
wpa_printf(MSG_ERROR,
"hostapd-ctrl-iface: bind(PF_UNIX): %s",
strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG,
"Successfully replaced leftover ctrl_iface socket '%s'",
fname);
} else {
wpa_printf(MSG_INFO,
"ctrl_iface exists and seems to be in use - cannot override it");
wpa_printf(MSG_INFO,
"Delete '%s' manually if it is not used anymore", fname);
os_free(fname);
fname = NULL;
goto fail;
}
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
os_free(fname);
mld->ctrl_sock = s;
if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld,
NULL) < 0)
return -1;
return 0;
fail:
if (s >= 0)
close(s);
if (fname) {
unlink(fname);
os_free(fname);
}
return -1;
#endif /* !CONFIG_CTRL_IFACE_UDP */
return 0;
}
void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld)
{
#ifndef CONFIG_CTRL_IFACE_UDP
struct wpa_ctrl_dst *dst, *prev;
if (mld->ctrl_sock > -1) {
char *fname;
eloop_unregister_read_sock(mld->ctrl_sock);
close(mld->ctrl_sock);
mld->ctrl_sock = -1;
fname = hostapd_mld_ctrl_iface_path(mld);
if (fname) {
unlink(fname);
os_free(fname);
}
if (mld->ctrl_interface &&
rmdir(mld->ctrl_interface) < 0) {
if (errno == ENOTEMPTY) {
wpa_printf(MSG_DEBUG,
"MLD control interface directory not empty - leaving it behind");
} else {
wpa_printf(MSG_ERROR,
"rmdir[ctrl_interface=%s]: %s",
mld->ctrl_interface,
strerror(errno));
}
}
}
dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst,
list)
os_free(dst);
#endif /* !CONFIG_CTRL_IFACE_UDP */
os_free(mld->ctrl_interface);
}
#endif /* CONFIG_IEEE80211BE */
#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
{
char *buf;
size_t len;
const char *ctrl_sock_iface;
#ifdef CONFIG_IEEE80211BE
ctrl_sock_iface = hapd->ctrl_sock_iface;
#else /* CONFIG_IEEE80211BE */
ctrl_sock_iface = hapd->conf->iface;
#endif /* CONFIG_IEEE80211BE */
if (hapd->conf->ctrl_interface == NULL)
return NULL;
len = os_strlen(hapd->conf->ctrl_interface) +
os_strlen(hapd->conf->iface) + 2;
os_strlen(ctrl_sock_iface) + 2;
buf = os_malloc(len);
if (buf == NULL)
return NULL;
os_snprintf(buf, len, "%s/%s",
hapd->conf->ctrl_interface, hapd->conf->iface);
hapd->conf->ctrl_interface, ctrl_sock_iface);
buf[len - 1] = '\0';
return buf;
}
@ -4814,6 +5203,7 @@ fail:
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
size_t iflen;
if (hapd->ctrl_sock > -1) {
wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
@ -4868,8 +5258,13 @@ fail:
}
#endif /* ANDROID */
#ifdef CONFIG_IEEE80211BE
iflen = os_strlen(hapd->ctrl_sock_iface);
#else /* CONFIG_IEEE80211BE */
iflen = os_strlen(hapd->conf->iface);
#endif /* CONFIG_IEEE80211BE */
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
iflen >= sizeof(addr.sun_path))
goto fail;
s = socket(PF_UNIX, SOCK_DGRAM, 0);

View file

@ -14,6 +14,8 @@ 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);
int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld);
void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{

View file

@ -2298,6 +2298,67 @@ own_ip_addr=127.0.0.1
#
#ssid_protection=0
# RSNE/RSNXE override
#
# These parameters can be used to configure RSN parameters for STAs that support
# the override elements. The RSN parameters for STAs that do not support these
# mechanisms are configured in the referenced configuration parameters. The AP
# allows STAs to use either of the configured sets for negotiating RSN
# parameters.
#
# The main purpose of this mechanism is to make the AP look like it is using an
# older security mechanism (e.g., WPA2-Personal) to older STAs while allowing
# new stations use newer security mechanisms (e.g., WPA3-Personal) based on the
# override values. This might be needed to work around issues with deployed
# STAs that do not implement RSNE extensibility correctly and may fail to
# connect when the AP is using a transition mode like WPA3-Personal transition
# mode.
#
# Key management; see wpa_key_mgmt for RSNE configuration
#rsn_override_key_mgmt=<accepted key management algorithms>
#
# Pairwise cipher suites; see rsn_pairwise for RSNE configuration
#rsn_override_pairwise=<accepted cipher suites)
#
# Management frame protection (MFP/PMF); see ieee80211w for RSNE configuration
# 0 = disabled
# 1 = optional
# 2 = required
#rsn_override_mfp=<0/1/2>
#
# Second set of similar parameters. These are required to be used for
# Wi-Fi 7 (EHT/MLO) associations with RSN overriding and can optionally be used
# in cases that do not use Wi-Fi 7.
#rsn_override_key_mgmt_2
#rsn_override_pairwise_2
#rsn_override_mfp_2
#
# The RSNXE is normally included if any of the extended RSN capabilities is
# enabled/supported. When using RSN overriding, a separate RSNXOE is included
# and it may be more interoperable to omit the RSNXE completely. This
# configuration parameter can be used to do that.
# 0 = Include the RSNXE if any extended RSN capability is enabled/supported
# (default).
# 1 = Do not include the RSNXE.
#rsn_override_omit_rsnxe=0
#
# Example configuration for WPA2-Personal/PMF-optional in RSNE and
# WPA3-Personal/PMF-required/MLO in override elements
#wpa_key_mgmt=WPA-PSK
#rsn_pairwise=CCMP
#ieee80211w=1
#rsn_override_key_mgmt=SAE
#rsn_override_pairwise=GCMP-256
#rsn_override_mfp=2
#rsn_override_key_mgmt_2=SAE-EXT-KEY
#rsn_override_pairwise_2=GCMP-256
#rsn_override_mfp_2=2
#beacon_prot=1
#sae_groups=19 20
#sae_require_mfp=1
#sae_pwe=2
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)

View file

@ -54,7 +54,11 @@ static void usage(void)
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] "
"usage: hostapd_cli [-p<path>] [-i<ifname>] "
#ifdef CONFIG_IEEE80211BE
"[-l<link_id>] "
#endif /* CONFIG_IEEE80211BE */
"[-hvBr] "
"[-a<path>] \\\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
@ -74,7 +78,11 @@ static void usage(void)
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
" socket path)\n\n");
" socket path)\n"
#ifdef CONFIG_IEEE80211BE
" -l<link_id> Link ID of the interface in case of Multi-Link Operation\n"
#endif /* CONFIG_IEEE80211BE */
"\n");
print_help(stderr, NULL);
}
@ -2212,12 +2220,15 @@ int main(int argc, char *argv[])
int c;
int daemonize = 0;
int reconnect = 0;
#ifdef CONFIG_IEEE80211BE
int link_id = -1;
#endif /* CONFIG_IEEE80211BE */
if (os_program_init())
return -1;
for (;;) {
c = getopt(argc, argv, "a:BhG:i:p:P:rs:v");
c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@ -2252,6 +2263,11 @@ int main(int argc, char *argv[])
case 's':
client_socket_dir = optarg;
break;
#ifdef CONFIG_IEEE80211BE
case 'l':
link_id = atoi(optarg);
break;
#endif /* CONFIG_IEEE80211BE */
default:
usage();
return -1;
@ -2285,6 +2301,24 @@ int main(int argc, char *argv[])
closedir(dir);
}
}
#ifdef CONFIG_IEEE80211BE
if (link_id >= 0 && ctrl_ifname) {
int ret;
char buf[300];
ret = os_snprintf(buf, sizeof(buf), "%s_%s%d",
ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME,
link_id);
if (os_snprintf_error(sizeof(buf), ret))
return -1;
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(buf);
link_id = -1;
}
#endif /* CONFIG_IEEE80211BE */
hostapd_cli_reconnect(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)

View file

@ -191,7 +191,6 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
os_memcpy(hapd->own_addr, b, ETH_ALEN);
}
hostapd_mld_add_link(hapd);
wpa_printf(MSG_DEBUG,
"Setup of non first link (%d) BSS of MLD %s",
hapd->mld_link_id, hapd->conf->iface);
@ -278,7 +277,6 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
else
os_memcpy(hapd->own_addr, b, ETH_ALEN);
hostapd_mld_add_link(hapd);
wpa_printf(MSG_DEBUG, "Setup of first link (%d) BSS of MLD %s",
hapd->mld_link_id, hapd->conf->iface);
}
@ -338,8 +336,14 @@ setup_mld:
hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr),
MAC2STR(hapd->own_addr));
hostapd_drv_link_add(hapd, hapd->mld_link_id,
hapd->own_addr);
if (hostapd_drv_link_add(hapd, hapd->mld_link_id,
hapd->own_addr)) {
wpa_printf(MSG_ERROR,
"MLD: Failed to add link %d in MLD %s",
hapd->mld_link_id, hapd->conf->iface);
return -1;
}
hostapd_mld_add_link(hapd);
}
#endif /* CONFIG_IEEE80211BE */
@ -748,6 +752,7 @@ static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces)
if (!interfaces->mld[i])
continue;
interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]);
os_free(interfaces->mld[i]);
interfaces->mld[i] = NULL;
}
@ -793,6 +798,10 @@ int main(int argc, char *argv[])
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
#ifdef CONFIG_IEEE80211BE
interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init;
interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit;
#endif /* CONFIG_IEEE80211BE */
dl_list_init(&interfaces.global_ctrl_dst);
#ifdef CONFIG_ETH_P_OUI
dl_list_init(&interfaces.eth_p_oui);

View file

@ -112,14 +112,8 @@ static void set_sta_weights(struct hostapd_data *hapd, unsigned int weight)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
unsigned int sta_weight = weight;
if (sta->dyn_airtime_weight)
sta_weight = (weight * sta->dyn_airtime_weight) / 256;
sta_set_airtime_weight(hapd, sta, sta_weight);
}
for (sta = hapd->sta_list; sta; sta = sta->next)
sta_set_airtime_weight(hapd, sta, weight);
}
@ -250,10 +244,7 @@ int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta)
unsigned int weight;
if (hapd->iconf->airtime_mode == AIRTIME_MODE_STATIC) {
if (sta->dyn_airtime_weight)
weight = sta->dyn_airtime_weight;
else
weight = get_weight_for_sta(hapd, sta->addr);
weight = get_weight_for_sta(hapd, sta->addr);
if (weight)
return sta_set_airtime_weight(hapd, sta, weight);
}

View file

@ -491,20 +491,33 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
#ifdef CONFIG_SAE
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
int *groups = conf->sae_groups;
int default_groups[] = { 19, 0, 0 };
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) &&
!wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2) &&
!hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
!wpa_key_mgmt_sae(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2))
return 0; /* PT not needed */
if (!groups) {
groups = default_groups;
if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2))
default_groups[1] = 20;
}
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
if (ssid->wpa_passphrase) {
ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
ssid->ssid_len,
ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
(const u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase),
NULL);
@ -514,8 +527,7 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
for (pw = conf->sae_passwords; pw; pw = pw->next) {
sae_deinit_pt(pw->pt);
pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
ssid->ssid_len,
pw->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
(const u8 *) pw->password,
os_strlen(pw->password),
pw->identifier);
@ -960,6 +972,11 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->rsne_override);
wpabuf_free(conf->rsnoe_override);
wpabuf_free(conf->rsno2e_override);
wpabuf_free(conf->rsnxe_override);
wpabuf_free(conf->rsnxoe_override);
wpabuf_free(conf->sae_commit_override);
wpabuf_free(conf->rsne_override_eapol);
wpabuf_free(conf->rsnxe_override_eapol);

View file

@ -358,7 +358,11 @@ struct hostapd_bss_config {
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int extended_key_id;
int wpa_key_mgmt;
int rsn_override_key_mgmt;
int rsn_override_key_mgmt_2;
enum mfp_options ieee80211w;
enum mfp_options rsn_override_mfp;
enum mfp_options rsn_override_mfp_2;
int group_mgmt_cipher;
int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
@ -387,9 +391,13 @@ struct hostapd_bss_config {
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_override_pairwise;
int rsn_override_pairwise_2;
int rsn_preauth;
char *rsn_preauth_interfaces;
int rsn_override_omit_rsnxe;
#ifdef CONFIG_IEEE80211R_AP
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@ -688,6 +696,11 @@ struct hostapd_bss_config {
u8 bss_load_test[5];
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
struct wpabuf *rsne_override;
struct wpabuf *rsnoe_override;
struct wpabuf *rsno2e_override;
struct wpabuf *rsnxe_override;
struct wpabuf *rsnxoe_override;
int sae_reflection_attack;
int sae_commit_status;
int sae_pk_omit;
@ -712,6 +725,7 @@ struct hostapd_bss_config {
struct wpabuf *eapol_m1_elements;
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
bool eapol_key_reserved_random;
int test_assoc_comeback_type;
struct wpabuf *presp_elements;

View file

@ -1250,3 +1250,14 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, &params);
}
#endif /* CONFIG_PASN */
struct hostapd_multi_hw_info *
hostapd_get_multi_hw_info(struct hostapd_data *hapd,
unsigned int *num_multi_hws)
{
if (!hapd->driver || !hapd->driver->get_multi_hw_info)
return NULL;
return hapd->driver->get_multi_hw_info(hapd->drv_priv, num_multi_hws);
}

View file

@ -478,4 +478,8 @@ static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211BE */
struct hostapd_multi_hw_info *
hostapd_get_multi_hw_info(struct hostapd_data *hapd,
unsigned int *num_multi_hws);
#endif /* AP_DRV_OPS */

View file

@ -403,6 +403,81 @@ static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
}
static u8 * hostapd_get_rsne_override(struct hostapd_data *hapd, u8 *pos,
size_t len)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
if (!ie || 2U + ie[1] > len)
return pos;
os_memcpy(pos, ie, 2 + ie[1]);
return pos + 2 + ie[1];
}
static u8 * hostapd_get_rsne_override_2(struct hostapd_data *hapd, u8 *pos,
size_t len)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
if (!ie || 2U + ie[1] > len)
return pos;
os_memcpy(pos, ie, 2 + ie[1]);
return pos + 2 + ie[1];
}
static u8 * hostapd_get_rsnxe_override(struct hostapd_data *hapd, u8 *pos,
size_t len)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (!ie || 2U + ie[1] > len)
return pos;
os_memcpy(pos, ie, 2 + ie[1]);
return pos + 2 + ie[1];
}
static size_t hostapd_get_rsne_override_len(struct hostapd_data *hapd)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
if (!ie)
return 0;
return 2 + ie[1];
}
static size_t hostapd_get_rsne_override_2_len(struct hostapd_data *hapd)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
if (!ie)
return 0;
return 2 + ie[1];
}
static size_t hostapd_get_rsnxe_override_len(struct hostapd_data *hapd)
{
const u8 *ie;
ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (!ie)
return 0;
return 2 + ie[1];
}
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
#ifdef CONFIG_TESTING_OPTIONS
@ -439,6 +514,35 @@ static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
}
static u8 * hostapd_eid_max_cs_time(struct hostapd_data *hapd, u8 *eid)
{
#ifdef CONFIG_IEEE80211BE
u32 switch_time;
/* Add Max Channel Switch Time element only if this AP is affiliated
* with an AP MLD and channel switch is in process. */
if (!hapd->conf->mld_ap || !hapd->cs_freq_params.channel)
return eid;
/* Switch time is basically time between CSA count 1 and CSA count
* 0 (1 beacon interval) + time for interface restart + time to
* send a Beacon frame in the new channel (1 beacon interval).
*
* TODO: Use dynamic interface restart time. For now, assume 1 sec.
*/
switch_time = USEC_TO_TU(1000 * 1000) + 2 * hapd->iconf->beacon_int;
*eid++ = WLAN_EID_EXTENSION;
*eid++ = 4;
*eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME;
WPA_PUT_LE24(eid, switch_time);
eid += 3;
#endif /* CONFIG_IEEE80211BE */
return eid;
}
static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
{
u8 op_class, channel;
@ -601,7 +705,6 @@ struct probe_resp_params {
bool is_p2p;
/* Generated IEs will be included inside an ML element */
bool is_ml_sta_info;
struct hostapd_data *mld_ap;
struct mld_info *mld_info;
@ -623,7 +726,7 @@ static void hostapd_free_probe_resp_params(struct probe_resp_params *params)
#ifdef CONFIG_IEEE80211BE
if (!params)
return;
ap_sta_free_sta_profile(params->mld_info);
os_free(params->mld_info);
params->mld_info = NULL;
#endif /* CONFIG_IEEE80211BE */
@ -662,17 +765,21 @@ static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
struct hostapd_data *ml_elem_ap =
params->mld_ap ? params->mld_ap : hapd;
buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
buflen += 3 + sizeof(struct ieee80211_eht_operation);
if (hapd->iconf->punct_bitmap)
buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
if (!params->is_ml_sta_info && hapd->conf->mld_ap) {
struct hostapd_data *ml_elem_ap =
params->mld_ap ? params->mld_ap : hapd;
if (ml_elem_ap->conf->mld_ap) {
buflen += hostapd_eid_eht_ml_beacon_len(
ml_elem_ap, params->mld_info, !!params->mld_ap);
/* For Max Channel Switch Time element during channel
* switch */
buflen += 6;
}
}
#endif /* CONFIG_IEEE80211BE */
@ -680,12 +787,13 @@ static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
params->known_bss,
params->known_bss_len, NULL);
if (!params->is_ml_sta_info)
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP,
true);
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP, true);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
buflen += hostapd_eid_dpp_cc_len(hapd);
buflen += hostapd_get_rsne_override_len(hapd);
buflen += hostapd_get_rsne_override_2_len(hapd);
buflen += hostapd_get_rsnxe_override_len(hapd);
return buflen;
}
@ -700,13 +808,11 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
epos = pos + len;
if (!params->is_ml_sta_info) {
*pos++ = WLAN_EID_SSID;
*pos++ = hapd->conf->ssid.ssid_len;
os_memcpy(pos, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
}
*pos++ = WLAN_EID_SSID;
*pos++ = hapd->conf->ssid.ssid_len;
os_memcpy(pos, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
/* Supported rates */
pos = hostapd_eid_supp_rates(hapd, pos);
@ -719,18 +825,13 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
/* Power Constraint element */
pos = hostapd_eid_pwr_constraint(hapd, pos);
/*
* CSA IE
* TODO: This should be included inside the ML sta profile
*/
if (!params->is_ml_sta_info) {
csa_pos = hostapd_eid_csa(hapd, pos);
if (csa_pos != pos)
params->csa_pos = csa_pos - 1;
else
params->csa_pos = NULL;
pos = csa_pos;
}
/* CSA element */
csa_pos = hostapd_eid_csa(hapd, pos);
if (csa_pos != pos)
params->csa_pos = csa_pos - 1;
else
params->csa_pos = NULL;
pos = csa_pos;
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
@ -746,18 +847,13 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
pos = hostapd_get_mde(hapd, pos, epos - pos);
/*
* eCSA IE
* TODO: This should be included inside the ML sta profile
*/
if (!params->is_ml_sta_info) {
csa_pos = hostapd_eid_ecsa(hapd, pos);
if (csa_pos != pos)
params->ecsa_pos = csa_pos - 1;
else
params->ecsa_pos = NULL;
pos = csa_pos;
}
/* eCSA element */
csa_pos = hostapd_eid_ecsa(hapd, pos);
if (csa_pos != pos)
params->ecsa_pos = csa_pos - 1;
else
params->ecsa_pos = NULL;
pos = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, pos);
pos = hostapd_eid_ht_capabilities(hapd, pos);
@ -799,12 +895,14 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
pos = hostapd_eid_txpower_envelope(hapd, pos);
#endif /* CONFIG_IEEE80211AX */
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
pos = hostapd_eid_chsw_wrapper(hapd, pos);
if (!params->is_ml_sta_info)
pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP,
true);
pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, true);
pos = hostapd_eid_fils_indic(hapd, pos, 0);
/* Max Channel Switch Time element */
pos = hostapd_eid_max_cs_time(hapd, pos);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
@ -885,6 +983,10 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
pos = hostapd_eid_owe_trans(hapd, pos, epos - pos);
pos = hostapd_eid_dpp_cc(hapd, pos, epos - pos);
pos = hostapd_get_rsne_override(hapd, pos, epos - pos);
pos = hostapd_get_rsne_override_2(hapd, pos, epos - pos);
pos = hostapd_get_rsnxe_override(hapd, pos, epos - pos);
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@ -957,7 +1059,6 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
int mld_id, u16 links)
{
struct probe_resp_params sta_info_params;
struct hostapd_data *link;
params->mld_ap = NULL;
@ -971,10 +1072,7 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
for_each_mld_link(link, hapd) {
struct mld_link_info *link_info;
size_t buflen;
u8 mld_link_id = link->mld_link_id;
u8 *epos;
u8 buf[EHT_ML_MAX_STA_PROF_LEN];
/*
* Set mld_ap iff the ML probe request explicitly
@ -994,49 +1092,12 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
continue;
link_info = &params->mld_info->links[mld_link_id];
sta_info_params.req = params->req;
sta_info_params.is_p2p = false;
sta_info_params.is_ml_sta_info = true;
sta_info_params.mld_ap = NULL;
sta_info_params.mld_info = NULL;
buflen = MAX_PROBERESP_LEN;
buflen += hostapd_probe_resp_elems_len(link, &sta_info_params);
if (buflen > EHT_ML_MAX_STA_PROF_LEN) {
wpa_printf(MSG_DEBUG,
"MLD: Not including link %d in ML probe response (%zu bytes is too long)",
mld_link_id, buflen);
goto fail;
}
/*
* NOTE: This does not properly handle inheritance and
* various other things.
*/
link_info->valid = true;
epos = buf;
/* Capabilities is the only fixed parameter */
WPA_PUT_LE16(epos, hostapd_own_capab_info(hapd));
epos += 2;
epos = hostapd_probe_resp_fill_elems(
link, &sta_info_params, epos,
EHT_ML_MAX_STA_PROF_LEN - 2);
link_info->resp_sta_profile_len = epos - buf;
os_free(link_info->resp_sta_profile);
link_info->resp_sta_profile = os_memdup(
buf, link_info->resp_sta_profile_len);
if (!link_info->resp_sta_profile)
link_info->resp_sta_profile_len = 0;
os_memcpy(link_info->local_addr, link->own_addr, ETH_ALEN);
os_memcpy(link_info, &hapd->partner_links[mld_link_id],
sizeof(hapd->partner_links[mld_link_id]));
wpa_printf(MSG_DEBUG,
"MLD: ML probe response includes link sta info for %d: %u bytes (estimate %zu)",
mld_link_id, link_info->resp_sta_profile_len,
buflen);
"MLD: ML probe response includes link STA info for %d: %u bytes",
mld_link_id, link_info->resp_sta_profile_len);
}
if (mld_id != -1 && !params->mld_ap) {
@ -1357,12 +1418,6 @@ void handle_probe_req(struct hostapd_data *hapd,
int mld_id;
u16 links;
#endif /* CONFIG_IEEE80211BE */
struct hostapd_ubus_request req = {
.type = HOSTAPD_UBUS_PROBE_REQ,
.mgmt_frame = mgmt,
.ssi_signal = ssi_signal,
.elems = &elems,
};
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
@ -1549,12 +1604,6 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
if (hostapd_ubus_handle_event(hapd, &req)) {
wpa_printf(MSG_DEBUG, "Probe request for " MACSTR " rejected by ubus handler.\n",
MAC2STR(mgmt->sa));
return;
}
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
@ -1615,7 +1664,6 @@ void handle_probe_req(struct hostapd_data *hapd,
params.is_p2p = !!elems.p2p;
params.known_bss = elems.mbssid_known_bss;
params.known_bss_len = elems.mbssid_known_bss_len;
params.is_ml_sta_info = false;
hostapd_gen_probe_resp(hapd, &params);
@ -1696,7 +1744,6 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
params.is_p2p = false;
params.known_bss = NULL;
params.known_bss_len = 0;
params.is_ml_sta_info = false;
params.mld_ap = NULL;
params.mld_info = NULL;
@ -1740,7 +1787,6 @@ u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
probe_params.is_p2p = false;
probe_params.known_bss = NULL;
probe_params.known_bss_len = 0;
probe_params.is_ml_sta_info = false;
probe_params.mld_ap = NULL;
probe_params.mld_info = NULL;
@ -2118,7 +2164,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
#define BEACON_TAIL_BUF_SIZE 1500
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
tail_len = BEACON_TAIL_BUF_SIZE;
#ifdef CONFIG_WPS
@ -2157,8 +2203,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
* long based on the common info and number of per
* station profiles. For now use 256.
*/
if (hapd->conf->mld_ap)
if (hapd->conf->mld_ap) {
tail_len += 256;
/* for Max Channel Switch Time element during channel
* switch */
tail_len += 6;
}
}
#endif /* CONFIG_IEEE80211BE */
@ -2169,6 +2220,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
tail_len += hostapd_eid_dpp_cc_len(hapd);
tail_len += hostapd_get_rsne_override_len(hapd);
tail_len += hostapd_get_rsne_override_2_len(hapd);
tail_len += hostapd_get_rsnxe_override_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@ -2299,10 +2353,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
#endif /* CONFIG_IEEE80211AX */
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
tailpos = hostapd_eid_chsw_wrapper(hapd, tailpos);
tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
/* Max Channel Switch Time element */
tailpos = hostapd_eid_max_cs_time(hapd, tailpos);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_mbssid_config(hapd, tailpos,
params->mbssid_elem_count);
@ -2380,6 +2438,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tail + tail_len - tailpos);
tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_get_rsne_override(hapd, tailpos,
tail + tail_len - tailpos);
tailpos = hostapd_get_rsne_override_2(hapd, tailpos,
tail + tail_len - tailpos);
tailpos = hostapd_get_rsnxe_override(hapd, tailpos,
tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@ -2412,7 +2477,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* If SAE offload is enabled, provide password to lower layer for
* SAE authentication and PMK generation.
*/
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
hapd->conf->rsn_override_key_mgmt |
hapd->conf->rsn_override_key_mgmt_2) &&
(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
if (hostapd_sae_pk_in_use(hapd->conf)) {
wpa_printf(MSG_ERROR,
@ -2457,7 +2524,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
else if (hapd->conf->wpa & WPA_PROTO_WPA)
params->pairwise_ciphers = hapd->conf->wpa_pairwise;
params->group_cipher = hapd->conf->wpa_group;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt |
hapd->conf->rsn_override_key_mgmt |
hapd->conf->rsn_override_key_mgmt_2;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
params->privacy = hapd->conf->wpa;
@ -2691,12 +2760,438 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211BE
static int hostapd_get_probe_resp_tmpl(struct hostapd_data *hapd,
struct probe_resp_params *params,
bool is_ml_sta_info)
{
os_memset(params, 0, sizeof(*params));
hostapd_gen_probe_resp(hapd, params);
if (!params->resp)
return -1;
/* The caller takes care of freeing params->resp. */
return 0;
}
static bool is_restricted_eid_in_sta_profile(u8 eid, bool tx_vap)
{
switch (eid) {
case WLAN_EID_TIM:
case WLAN_EID_BSS_MAX_IDLE_PERIOD:
case WLAN_EID_MULTIPLE_BSSID:
case WLAN_EID_REDUCED_NEIGHBOR_REPORT:
case WLAN_EID_NEIGHBOR_REPORT:
return true;
case WLAN_EID_SSID:
/* SSID is not restricted for non-transmitted BSSID */
return tx_vap;
default:
return false;
}
}
static bool is_restricted_ext_eid_in_sta_profile(u8 ext_id)
{
switch (ext_id) {
case WLAN_EID_EXT_MULTI_LINK:
return true;
default:
return false;
}
}
/* Create the link STA profiles based on inheritance from the reporting
* profile.
*
* NOTE: The same function is used for length calculation as well as filling
* data in the given buffer. This avoids risk of not updating the length
* function but filling function or vice versa.
*/
static size_t hostapd_add_sta_profile(struct ieee80211_mgmt *link_fdata,
size_t link_data_len,
struct ieee80211_mgmt *own_fdata,
size_t own_data_len,
u8 *sta_profile, bool tx_vap)
{
const struct element *link_elem;
size_t sta_profile_len = 0;
const u8 *link_elem_data;
u8 link_ele_len;
u8 *link_data;
const struct element *own_elem;
u8 link_eid, own_eid, own_ele_len;
const u8 *own_elem_data;
u8 *own_data;
bool is_ext;
bool ie_found;
u8 non_inherit_ele_ext_list[256] = { 0 };
u8 non_inherit_ele_ext_list_len = 0;
u8 non_inherit_ele_list[256] = { 0 };
u8 non_inherit_ele_list_len = 0;
u8 num_link_elem_vendor_ies = 0, num_own_elem_vendor_ies = 0;
bool add_vendor_ies = false, is_identical_vendor_ies = true;
/* The bitmap of parsed EIDs. There are 256 EIDs and ext EIDs, so 32
* bytes to store the bitmaps. */
u8 parsed_eid_bmap[32] = { 0 }, parsed_ext_eid_bmap[32] = { 0 };
/* extra len used in the logic includes the element id and len */
u8 extra_len = 2;
/* Include len for capab info */
sta_profile_len += sizeof(le16);
if (sta_profile) {
os_memcpy(sta_profile, &link_fdata->u.probe_resp.capab_info,
sizeof(le16));
sta_profile += sizeof(le16);
}
own_data = own_fdata->u.probe_resp.variable;
link_data = link_fdata->u.probe_resp.variable;
/* The below logic takes the reporting BSS data and reported BSS data
* and performs intersection to build the STA profile of the reported
* BSS. Certain elements are not added to the STA profile as
* recommended in standard. Matching element information in the
* reporting BSS profile are ignored in the STA profile. Remaining
* elements pertaining to the STA profile are appended at the end. */
for_each_element(own_elem, own_data, own_data_len) {
is_ext = false;
ie_found = false;
/* Pick one of own elements and get its EID and length */
own_elem_data = own_elem->data;
own_ele_len = own_elem->datalen;
if (own_elem->id == WLAN_EID_EXTENSION) {
is_ext = true;
own_eid = *(own_elem_data);
if (is_restricted_ext_eid_in_sta_profile(own_eid))
continue;
} else {
own_eid = own_elem->id;
if (is_restricted_eid_in_sta_profile(own_eid, tx_vap))
continue;
}
for_each_element(link_elem, link_data, link_data_len) {
/* If the element type mismatches, do not consider
* this link element for comparison. */
if ((link_elem->id == WLAN_EID_EXTENSION &&
!is_ext) ||
(is_ext && link_elem->id != WLAN_EID_EXTENSION))
continue;
/* Comparison can be done so get the link element and
* its EID and length. */
link_elem_data = link_elem->data;
link_ele_len = link_elem->datalen;
if (link_elem->id == WLAN_EID_EXTENSION)
link_eid = *(link_elem_data);
else
link_eid = link_elem->id;
/* Ignore if EID does not match */
if (own_eid != link_eid)
continue;
ie_found = true;
/* Ignore if the contents is identical. */
if (own_ele_len == link_ele_len &&
os_memcmp(own_elem->data, link_elem->data,
own_ele_len) == 0) {
if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
is_identical_vendor_ies = true;
num_own_elem_vendor_ies++;
}
continue;
}
/* No need to include this non-matching Vendor Specific
* element explicitly at this point. */
if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
is_identical_vendor_ies = false;
continue;
}
/* This element is present in the reported profile
* as well as present in the reporting profile.
* However, there is a mismatch in the contents and
* hence, include this in the per STA profile. */
sta_profile_len += link_ele_len + extra_len;
if (sta_profile) {
os_memcpy(sta_profile,
link_elem->data - extra_len,
link_ele_len + extra_len);
sta_profile += link_ele_len + extra_len;
}
/* Update the parsed EIDs bitmap */
if (is_ext)
parsed_ext_eid_bmap[own_eid / 8] |=
BIT(own_eid % 8);
else
parsed_eid_bmap[own_eid / 8] |=
BIT(own_eid % 8);
break;
}
/* We found at least one Vendor Specific element in reporting
* link which is not same (or present) in the reported link. We
* need to include all Vendor Specific elements from the
* reported link. */
if (!is_identical_vendor_ies)
add_vendor_ies = true;
/* This is a unique element in the reporting profile which is
* not present in the reported profile. Update the
* non-inheritance list. */
if (!ie_found) {
u8 idx;
if (is_ext) {
idx = non_inherit_ele_ext_list_len++;
non_inherit_ele_ext_list[idx] = own_eid;
} else {
idx = non_inherit_ele_list_len++;
non_inherit_ele_list[idx] = own_eid;
}
}
}
/* Parse the remaining elements in the reported profile */
for_each_element(link_elem, link_data, link_data_len) {
link_elem_data = link_elem->data;
link_ele_len = link_elem->datalen;
/* No need to check this Vendor Specific element at this point.
* Just take the count and continue. */
if (link_elem->id == WLAN_EID_VENDOR_SPECIFIC) {
num_link_elem_vendor_ies++;
continue;
}
if (link_elem->id == WLAN_EID_EXTENSION) {
link_eid = *(link_elem_data);
if ((parsed_ext_eid_bmap[link_eid / 8] &
BIT(link_eid % 8)) ||
is_restricted_ext_eid_in_sta_profile(link_eid))
continue;
} else {
link_eid = link_elem->id;
if ((parsed_eid_bmap[link_eid / 8] &
BIT(link_eid % 8)) ||
is_restricted_eid_in_sta_profile(link_eid, tx_vap))
continue;
}
sta_profile_len += link_ele_len + extra_len;
if (sta_profile) {
os_memcpy(sta_profile, link_elem_data - extra_len,
link_ele_len + extra_len);
sta_profile += link_ele_len + extra_len;
}
}
/* Handle Vendor Specific elements
* Add all the Vendor Specific elements of the reported link if
* a. There is at least one non-matching Vendor Specific element, or
* b. The number of Vendor Specific elements in reporting and reported
* link is not same. */
if (add_vendor_ies ||
num_own_elem_vendor_ies != num_link_elem_vendor_ies) {
for_each_element(link_elem, link_data, link_data_len) {
link_elem_data = link_elem->data;
link_ele_len = link_elem->datalen;
if (link_elem->id != WLAN_EID_VENDOR_SPECIFIC)
continue;
sta_profile_len += link_ele_len + extra_len;
if (sta_profile) {
os_memcpy(sta_profile,
link_elem_data - extra_len,
link_ele_len + extra_len);
sta_profile += link_ele_len + extra_len;
}
}
}
/* Handle non-inheritance
* Non-Inheritance element:
* Element ID Ext: 1 octet
* Length: 1 octet
* Ext tag number: 1 octet
* Length of Elements ID list: 1 octet
* Elements ID list: variable
* Length of Elements ID Extension list: 1 octet
* Elements ID extensions list: variable
*/
if (non_inherit_ele_list_len || non_inherit_ele_ext_list_len)
sta_profile_len += 3 + 2 + non_inherit_ele_list_len +
non_inherit_ele_ext_list_len;
if (sta_profile &&
(non_inherit_ele_list_len || non_inherit_ele_ext_list_len)) {
*sta_profile++ = WLAN_EID_EXTENSION;
*sta_profile++ = non_inherit_ele_list_len +
non_inherit_ele_ext_list_len + 3;
*sta_profile++ = WLAN_EID_EXT_NON_INHERITANCE;
*sta_profile++ = non_inherit_ele_list_len;
os_memcpy(sta_profile, non_inherit_ele_list,
non_inherit_ele_list_len);
sta_profile += non_inherit_ele_list_len;
*sta_profile++ = non_inherit_ele_ext_list_len;
os_memcpy(sta_profile, non_inherit_ele_ext_list,
non_inherit_ele_ext_list_len);
sta_profile += non_inherit_ele_ext_list_len;
}
return sta_profile_len;
}
static u8 * hostapd_gen_sta_profile(struct ieee80211_mgmt *link_data,
size_t link_data_len,
struct ieee80211_mgmt *own_data,
size_t own_data_len,
size_t *sta_profile_len, bool tx_vap)
{
u8 *sta_profile;
/* Get the length first */
*sta_profile_len = hostapd_add_sta_profile(link_data, link_data_len,
own_data, own_data_len,
NULL, tx_vap);
if (!(*sta_profile_len) || *sta_profile_len > EHT_ML_MAX_STA_PROF_LEN)
return NULL;
sta_profile = os_zalloc(*sta_profile_len);
if (!sta_profile)
return NULL;
/* Now fill in the data */
hostapd_add_sta_profile(link_data, link_data_len, own_data,
own_data_len, sta_profile, tx_vap);
/* The caller takes care of freeing the returned sta_profile */
return sta_profile;
}
static void hostapd_gen_per_sta_profiles(struct hostapd_data *hapd)
{
bool tx_vap = hapd == hostapd_mbssid_get_tx_bss(hapd);
size_t link_data_len, sta_profile_len;
size_t own_data_len;
struct probe_resp_params link_params;
struct probe_resp_params own_params;
struct ieee80211_mgmt *link_data;
struct ieee80211_mgmt *own_data;
struct mld_link_info *link_info;
struct hostapd_data *link_bss;
u8 link_id, *sta_profile;
if (!hapd->conf->mld_ap)
return;
wpa_printf(MSG_DEBUG, "MLD: Generating per STA profiles for MLD %s",
hapd->conf->iface);
wpa_printf(MSG_DEBUG, "MLD: Reporting link %d", hapd->mld_link_id);
/* Generate a Probe Response template for self */
if (hostapd_get_probe_resp_tmpl(hapd, &own_params, false)) {
wpa_printf(MSG_ERROR,
"MLD: Error in building per STA profiles");
return;
}
own_data = own_params.resp;
own_data_len = own_params.resp_len;
/* Consider the length of the variable fields */
own_data_len -= offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
for_each_mld_link(link_bss, hapd) {
if (link_bss == hapd || !link_bss->started)
continue;
link_id = link_bss->mld_link_id;
if (link_id > MAX_NUM_MLD_LINKS)
continue;
sta_profile = NULL;
sta_profile_len = 0;
/* Generate a Probe Response frame template for partner link */
if (hostapd_get_probe_resp_tmpl(link_bss, &link_params, true)) {
wpa_printf(MSG_ERROR,
"MLD: Could not get link STA probe response template for link %d",
link_id);
continue;
}
link_data = link_params.resp;
link_data_len = link_params.resp_len;
/* Consider length of the variable fields */
link_data_len -= offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
own_data, own_data_len,
&sta_profile_len, tx_vap);
if (!sta_profile) {
wpa_printf(MSG_ERROR,
"MLD: Could not generate link STA profile for link %d",
link_id);
continue;
}
link_info = &hapd->partner_links[link_id];
link_info->valid = true;
os_free(link_info->resp_sta_profile);
link_info->resp_sta_profile_len = sta_profile_len;
link_info->resp_sta_profile = os_memdup(sta_profile,
sta_profile_len);
if (!link_info->resp_sta_profile)
link_info->resp_sta_profile_len = 0;
os_memcpy(link_info->local_addr, link_bss->own_addr, ETH_ALEN);
wpa_printf(MSG_DEBUG,
"MLD: Reported link STA info for %d: %u bytes",
link_id, link_info->resp_sta_profile_len);
os_free(sta_profile);
os_free(link_params.resp);
}
os_free(own_params.resp);
}
#endif /* CONFIG_IEEE80211BE */
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct hostapd_iface *iface = hapd->iface;
int ret;
size_t i, j;
bool is_6g, hapd_mld = false;
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *link_bss;
#endif /* CONFIG_IEEE80211BE */
ret = __ieee802_11_set_beacon(hapd);
if (ret != 0)
@ -2737,6 +3232,15 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
}
}
#ifdef CONFIG_IEEE80211BE
if (!hapd_mld)
return 0;
/* Generate per STA profiles for each affiliated APs */
for_each_mld_link(link_bss, hapd)
hostapd_gen_per_sta_profiles(link_bss);
#endif /* CONFIG_IEEE80211BE */
return 0;
}

View file

@ -661,15 +661,18 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
if (os_strstr(txtaddr, " tx=0"))
hostapd_drv_sta_remove(hapd, addr);
else
hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
if (os_strstr(txtaddr, " tx=0")) {
hostapd_drv_sta_remove(hapd, addr);
if (sta)
ap_free_sta(hapd, sta);
} else {
hostapd_drv_sta_deauth(hapd, addr, reason);
if (sta)
ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
}
return 0;
}
@ -723,15 +726,18 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
if (os_strstr(txtaddr, " tx=0"))
hostapd_drv_sta_remove(hapd, addr);
else
hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
if (os_strstr(txtaddr, " tx=0")) {
hostapd_drv_sta_remove(hapd, addr);
if (sta)
ap_free_sta(hapd, sta);
} else {
hostapd_drv_sta_disassoc(hapd, addr, reason);
if (sta)
ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
}
return 0;
}
@ -1137,8 +1143,9 @@ int hostapd_parse_csa_settings(const char *pos,
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->freq_params.he_enabled = !!os_strstr(pos, " he") ||
settings->freq_params.eht_enabled;
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
#undef SET_CSA_SETTING_EXT

View file

@ -253,6 +253,13 @@ static int dfs_find_channel(struct hostapd_iface *iface,
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
wpa_printf(MSG_DEBUG,
"DFS: channel %d (%d) is not under current hardware index",
chan->freq, chan->chan);
continue;
}
/* Skip HT40/VHT incompatible channels */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
@ -1218,8 +1225,6 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
hostapd_ubus_notify_radar_detected(iface, freq, chan_width, cf1, cf2);
/* Proceed only if DFS is not offloaded to the driver */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return 0;

View file

@ -73,6 +73,8 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
elems.fils_session,
sta->fils_hlp_resp);
if (!p)
return;
reply_res = hostapd_sta_assoc(hapd, sta->addr,
sta->fils_pending_assoc_is_reassoc,
@ -248,6 +250,52 @@ out:
#endif /* CONFIG_IEEE80211BE */
#if defined(HOSTAPD) || defined(CONFIG_IEEE80211BE)
static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
const u8 *src, bool rsn,
struct sta_info **sta_ret)
{
struct hostapd_data *hapd;
struct sta_info *sta;
unsigned int j;
if (sta_ret)
*sta_ret = NULL;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
sta = ap_get_sta(hapd, src);
if (sta && (sta->flags & WLAN_STA_ASSOC) &&
(!rsn || sta->wpa_sm)) {
if (sta_ret)
*sta_ret = sta;
return hapd;
}
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
struct hostapd_data *p_hapd;
for_each_mld_link(p_hapd, hapd) {
if (p_hapd == hapd)
continue;
sta = ap_get_sta(p_hapd, src);
if (sta && (sta->flags & WLAN_STA_ASSOC) &&
(!rsn || sta->wpa_sm)) {
if (sta_ret)
*sta_ret = sta;
return p_hapd;
}
}
}
#endif /* CONFIG_IEEE80211BE */
}
return NULL;
}
#endif /* HOSTAPD || CONFIG_IEEE80211BE */
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len,
const u8 *resp_ies, size_t resp_ies_len,
@ -268,10 +316,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
struct hostapd_iface *iface = hapd->iface;
#endif /* CONFIG_OWE */
bool updated = false;
struct hostapd_ubus_request req = {
.type = HOSTAPD_UBUS_ASSOC_REQ,
.addr = addr,
};
if (addr == NULL) {
/*
@ -416,12 +460,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
if (hostapd_ubus_handle_event(hapd, &req)) {
wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n",
MAC2STR(req.addr));
goto fail;
}
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
@ -523,6 +561,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
"Failed to initialize WPA state machine");
return -1;
}
wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
elems.rsn_selection_len);
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
wpa_printf(MSG_DEBUG,
@ -783,6 +823,9 @@ skip_wpa_check:
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
elems.fils_session,
sta->fils_hlp_resp);
if (!p)
goto fail;
wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
buf, p - buf);
}
@ -1047,6 +1090,20 @@ legacy:
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *orig_hapd = hapd;
if (!sta && hapd->conf->mld_ap) {
hapd = hostapd_find_by_sta(hapd->iface, addr, true, &sta);
if (!hapd) {
wpa_printf(MSG_DEBUG,
"No partner link BSS found for STA " MACSTR
" - fallback to received context",
MAC2STR(addr));
hapd = orig_hapd;
}
}
#endif /* CONFIG_IEEE80211BE */
if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
return;
@ -1989,50 +2046,6 @@ static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
}
static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
const u8 *src, bool rsn,
struct sta_info **sta_ret)
{
struct hostapd_data *hapd;
struct sta_info *sta;
unsigned int j;
if (sta_ret)
*sta_ret = NULL;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
sta = ap_get_sta(hapd, src);
if (sta && (sta->flags & WLAN_STA_ASSOC) &&
(!rsn || sta->wpa_sm)) {
if (sta_ret)
*sta_ret = sta;
return hapd;
}
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
struct hostapd_data *p_hapd;
for_each_mld_link(p_hapd, hapd) {
if (p_hapd == hapd)
continue;
sta = ap_get_sta(p_hapd, src);
if (sta && (sta->flags & WLAN_STA_ASSOC) &&
(!rsn || sta->wpa_sm)) {
if (sta_ret)
*sta_ret = sta;
return p_hapd;
}
}
}
#endif /* CONFIG_IEEE80211BE */
}
return NULL;
}
static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
const u8 *data, size_t data_len,
enum frame_encryption encrypted,
@ -2419,6 +2432,88 @@ static void hostapd_event_color_change(struct hostapd_data *hapd, bool success)
#endif /* CONFIG_IEEE80211AX */
static void hostapd_iface_enable(struct hostapd_data *hapd)
{
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
if (hapd->disabled && hapd->started) {
hapd->disabled = 0;
/*
* Try to re-enable interface if the driver stopped it
* when the interface got disabled.
*/
if (hapd->wpa_auth)
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
else
hostapd_reconfig_encryption(hapd);
hapd->reenable_beacon = 1;
ieee802_11_set_beacon(hapd);
#ifdef NEED_AP_MLME
} else if (hapd->disabled && hapd->iface->cac_started) {
wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
hostapd_handle_dfs(hapd->iface);
#endif /* NEED_AP_MLME */
}
}
static void hostapd_iface_disable(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
hapd->disabled = 1;
}
#ifdef CONFIG_IEEE80211BE
static void hostapd_mld_iface_enable(struct hostapd_data *hapd)
{
struct hostapd_data *first_link, *link_bss;
first_link = hostapd_mld_is_first_bss(hapd) ? hapd :
hostapd_mld_get_first_bss(hapd);
/* Links have been removed. Re-add all links and enable them, but
* enable the first link BSS before doing that. */
if (hostapd_drv_link_add(first_link, first_link->mld_link_id,
first_link->own_addr)) {
wpa_printf(MSG_ERROR, "MLD: Failed to re-add link %d in MLD %s",
first_link->mld_link_id, first_link->conf->iface);
return;
}
hostapd_iface_enable(first_link);
/* Add other affiliated links */
for_each_mld_link(link_bss, first_link) {
if (link_bss == first_link)
continue;
if (hostapd_drv_link_add(link_bss, link_bss->mld_link_id,
link_bss->own_addr)) {
wpa_printf(MSG_ERROR,
"MLD: Failed to re-add link %d in MLD %s",
link_bss->mld_link_id,
link_bss->conf->iface);
continue;
}
hostapd_iface_enable(link_bss);
}
}
static void hostapd_mld_iface_disable(struct hostapd_data *hapd)
{
struct hostapd_data *link_bss;
for_each_mld_link(link_bss, hapd)
hostapd_iface_disable(link_bss);
}
#endif /* CONFIG_IEEE80211BE */
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@ -2696,30 +2791,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#endif /* NEED_AP_MLME */
case EVENT_INTERFACE_ENABLED:
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
if (hapd->disabled && hapd->started) {
hapd->disabled = 0;
/*
* Try to re-enable interface if the driver stopped it
* when the interface got disabled.
*/
if (hapd->wpa_auth)
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
else
hostapd_reconfig_encryption(hapd);
hapd->reenable_beacon = 1;
ieee802_11_set_beacon(hapd);
#ifdef NEED_AP_MLME
} else if (hapd->disabled && hapd->iface->cac_started) {
wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
hostapd_handle_dfs(hapd->iface);
#endif /* NEED_AP_MLME */
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
hostapd_mld_iface_enable(hapd);
break;
}
#endif /* CONFIG_IEEE80211BE */
hostapd_iface_enable(hapd);
break;
case EVENT_INTERFACE_DISABLED:
hostapd_free_stas(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
hapd->disabled = 1;
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap) {
hostapd_mld_iface_disable(hapd);
break;
}
#endif /* CONFIG_IEEE80211BE */
hostapd_iface_disable(hapd);
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
@ -2772,6 +2859,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
hostapd_event_color_change(hapd, true);
break;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211BE
case EVENT_MLD_INTERFACE_FREED:
wpa_printf(MSG_DEBUG, "MLD: Interface %s freed",
hapd->conf->iface);
hostapd_mld_interface_freed(hapd);
break;
#endif /* CONFIG_IEEE80211BE */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;

View file

@ -400,8 +400,6 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
#define TU_TO_USEC(_val) ((_val) * 1024)
static void hostapd_link_remove_timeout_handler(void *eloop_data,
void *user_ctx)
{
@ -440,6 +438,8 @@ int hostapd_link_remove(struct hostapd_data *hapd, u32 count)
hapd->eht_mld_link_removal_count = count;
hapd->eht_mld_bss_param_change++;
if (hapd->eht_mld_bss_param_change == 255)
hapd->eht_mld_bss_param_change = 0;
eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int),
hostapd_link_remove_timeout_handler,
@ -475,7 +475,6 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
hostapd_ubus_free_bss(hapd);
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@ -621,9 +620,19 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
int i;
if (!hapd->conf || !hapd->conf->mld_ap)
return;
/* Free per STA profiles */
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
os_free(hapd->partner_links[i].resp_sta_profile);
os_memset(&hapd->partner_links[i], 0,
sizeof(hapd->partner_links[i]));
}
/* Put all freeing logic above this */
if (!hapd->mld->num_links)
return;
@ -703,6 +712,9 @@ void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
ap_list_deinit(iface);
sta_track_deinit(iface);
airtime_policy_update_deinit(iface);
hostapd_free_multi_hw_info(iface->multi_hw_info);
iface->multi_hw_info = NULL;
iface->current_hw_info = NULL;
}
@ -1304,8 +1316,6 @@ static int hostapd_start_beacon(struct hostapd_data *hapd,
if (hapd->driver && hapd->driver->set_operstate)
hapd->driver->set_operstate(hapd->drv_priv, 1);
hostapd_ubus_add_bss(hapd);
return 0;
}
@ -1443,7 +1453,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
if (h_hapd) {
hapd->drv_priv = h_hapd->drv_priv;
hapd->interface_added = h_hapd->interface_added;
hostapd_mld_add_link(hapd);
wpa_printf(MSG_DEBUG,
"Setup of non first link (%d) BSS of MLD %s",
hapd->mld_link_id, hapd->conf->iface);
@ -1474,7 +1483,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
hapd->mld_link_id, hapd->conf->iface);
os_memcpy(hapd->mld->mld_addr, hapd->own_addr,
ETH_ALEN);
hostapd_mld_add_link(hapd);
}
#endif /* CONFIG_IEEE80211BE */
}
@ -1489,8 +1497,13 @@ setup_mld:
MAC2STR(hapd->own_addr));
if (hostapd_drv_link_add(hapd, hapd->mld_link_id,
hapd->own_addr))
hapd->own_addr)) {
wpa_printf(MSG_ERROR,
"MLD: Failed to add link %d in MLD %s",
hapd->mld_link_id, hapd->conf->iface);
return -1;
}
hostapd_mld_add_link(hapd);
}
#endif /* CONFIG_IEEE80211BE */
@ -1811,12 +1824,36 @@ int hostapd_set_acl(struct hostapd_data *hapd)
}
static int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
int ret;
if (hapd->conf->mld_ap) {
ret = os_snprintf(hapd->ctrl_sock_iface,
sizeof(hapd->ctrl_sock_iface), "%s_%s%d",
hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME,
hapd->mld_link_id);
if (os_snprintf_error(sizeof(hapd->ctrl_sock_iface), ret))
return -1;
} else {
os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface,
sizeof(hapd->ctrl_sock_iface));
}
#endif /* CONFIG_IEEE80211BE */
return 0;
}
static int start_ctrl_iface_bss(struct hostapd_data *hapd)
{
if (!hapd->iface->interfaces ||
!hapd->iface->interfaces->ctrl_iface_init)
return 0;
if (hostapd_set_ctrl_sock_iface(hapd))
return -1;
if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR,
"Failed to setup control interface for %s",
@ -1837,6 +1874,10 @@ static int start_ctrl_iface(struct hostapd_iface *iface)
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
if (hostapd_set_ctrl_sock_iface(hapd))
return -1;
if (iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR,
"Failed to setup control interface for %s",
@ -2484,7 +2525,6 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
if (err)
goto fail;
hostapd_ubus_add_iface(iface);
wpa_printf(MSG_DEBUG, "Completing interface initialization");
if (iface->freq) {
#ifdef NEED_AP_MLME
@ -2496,6 +2536,12 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
hostapd_hw_mode_txt(iface->conf->hw_mode),
iface->conf->channel, iface->freq);
if (hostapd_set_current_hw_info(iface, iface->freq)) {
wpa_printf(MSG_ERROR,
"Failed to set current hardware info");
goto fail;
}
#ifdef NEED_AP_MLME
/* Handle DFS only if it is not offloaded to the driver */
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
@ -2676,8 +2722,6 @@ dfs_offload:
#endif /* CONFIG_FST */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
// TODO: log everything in `hostapd_set_state` directly
hostapd_ubus_notify_readiness(hapd);
hostapd_owe_update_trans(iface);
airtime_policy_update_init(iface);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
@ -2706,7 +2750,6 @@ dfs_offload:
fail:
wpa_printf(MSG_ERROR, "Interface initialization failed");
hostapd_ubus_free_iface(iface);
if (iface->is_no_ir) {
hostapd_set_state(iface, HAPD_IFACE_NO_IR);
@ -3072,9 +3115,17 @@ static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
os_strlcpy(mld->name, conf->iface, sizeof(conf->iface));
dl_list_init(&mld->links);
mld->ctrl_sock = -1;
if (hapd->conf->ctrl_interface)
mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface);
wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name);
/* Initialize MLD control interfaces early to allow external monitoring
* of link setup operations. */
if (interfaces->mld_ctrl_iface_init(mld))
goto fail;
hapd->mld = mld;
hostapd_mld_ref_inc(mld);
hostapd_bss_alloc_link_id(hapd);
@ -3134,6 +3185,8 @@ static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces)
if (!remove && !forced_remove)
continue;
interfaces->mld_ctrl_iface_deinit(mld);
wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name,
forced_remove ? " (forced)" : "");
os_free(mld);
@ -3394,8 +3447,10 @@ static void hostapd_cleanup_driver(const struct wpa_driver_ops *driver,
driver->hapd_deinit(drv_priv);
} else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
driver->is_drv_shared &&
!driver->is_drv_shared(drv_priv, iface->bss[0])) {
!driver->is_drv_shared(drv_priv,
iface->bss[0]->mld_link_id)) {
driver->hapd_deinit(drv_priv);
hostapd_mld_interface_freed(iface->bss[0]);
} else if (hostapd_if_link_remove(iface->bss[0],
WPA_IF_AP_BSS,
iface->bss[0]->conf->iface,
@ -3423,7 +3478,6 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface)
(unsigned int) iface->conf->num_bss);
driver = iface->bss[0]->driver;
drv_priv = iface->bss[0]->drv_priv;
hostapd_ubus_free_iface(iface);
hostapd_interface_deinit(iface);
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
@ -4509,6 +4563,42 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
}
int hostapd_force_channel_switch(struct hostapd_iface *iface,
struct csa_settings settings)
{
int ret = 0;
if (!settings.freq_params.channel) {
/* Check if the new channel is supported */
settings.freq_params.channel = hostapd_hw_get_channel(
iface->bss[0], settings.freq_params.freq);
if (!settings.freq_params.channel)
return -1;
}
ret = hostapd_disable_iface(iface);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to disable the interface");
return ret;
}
hostapd_chan_switch_config(iface->bss[0], &settings.freq_params);
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
&settings.freq_params, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"Failed to set the new channel in config");
return ret;
}
ret = hostapd_enable_iface(iface);
if (ret)
wpa_printf(MSG_DEBUG, "Failed to enable the interface");
return ret;
}
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
@ -4940,6 +5030,18 @@ struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd)
return mld->fbss;
}
void hostapd_mld_interface_freed(struct hostapd_data *hapd)
{
struct hostapd_data *link_bss = NULL;
if (!hapd || !hapd->conf->mld_ap)
return;
for_each_mld_link(link_bss, hapd)
link_bss->drv_priv = NULL;
}
#endif /* CONFIG_IEEE80211BE */

View file

@ -18,7 +18,6 @@
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
#include "ubus.h"
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
@ -98,6 +97,8 @@ struct hapd_interfaces {
#ifdef CONFIG_IEEE80211BE
struct hostapd_mld **mld;
size_t mld_count;
int (*mld_ctrl_iface_init)(struct hostapd_mld *mld);
void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld);
#endif /* CONFIG_IEEE80211BE */
};
@ -168,23 +169,21 @@ struct hostapd_sae_commit_queue {
u8 msg[];
};
/**
* struct hostapd_liminix_stats - Liminix custom STA/AP statistics
* Inspired from the OpenWRT patch of David Bauer.
*/
struct hostapd_liminix_stats {
struct {
u64 neighbor_report_tx;
} rrm;
struct mld_link_info {
u8 valid:1;
u8 nstr_bitmap_len:2;
u8 local_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN];
struct {
u64 bss_transition_query_rx;
u64 bss_transition_request_tx;
u64 bss_transition_response_rx;
} wnm;
u8 nstr_bitmap[2];
u16 capability;
u16 status;
u16 resp_sta_profile_len;
u8 *resp_sta_profile;
};
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
@ -192,7 +191,6 @@ struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
@ -200,9 +198,6 @@ struct hostapd_data {
u8 own_addr[ETH_ALEN];
/* Liminix specific statistics */
struct hostapd_liminix_stats liminix_stats;
int num_sta; /* number of entries in sta_list */
struct sta_info *sta_list; /* STA info list head */
#define STA_HASH_SIZE 256
@ -498,6 +493,14 @@ struct hostapd_data {
struct hostapd_mld *mld;
struct dl_list link;
u8 mld_link_id;
/* Cached partner info for ML probe response */
struct mld_link_info partner_links[MAX_NUM_MLD_LINKS];
/* 5 characters for "_link", up to 2 characters for <link ID>, so in
* total, additional 7 characters required. */
char ctrl_sock_iface[IFNAMSIZ + 7 + 1];
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
@ -540,6 +543,10 @@ struct hostapd_mld {
struct hostapd_data *fbss;
struct dl_list links; /* List head of all affiliated links */
int ctrl_sock;
struct dl_list ctrl_dst;
char *ctrl_interface; /* Directory for UNIX domain sockets */
};
#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF
@ -733,6 +740,10 @@ struct hostapd_iface {
bool is_no_ir;
bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */
struct hostapd_multi_hw_info *multi_hw_info;
unsigned int num_multi_hws;
struct hostapd_multi_hw_info *current_hw_info;
};
/* hostapd.c */
@ -747,7 +758,6 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_bss_config *bss);
int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_set_own_neighbor_report(struct hostapd_data *hapd);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
struct hostapd_iface * hostapd_alloc_iface(void);
@ -776,6 +786,8 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd,
struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
int hostapd_force_channel_switch(struct hostapd_iface *iface,
struct csa_settings settings);
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
@ -854,6 +866,7 @@ int hostapd_fill_cca_settings(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE
bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
void hostapd_mld_interface_freed(struct hostapd_data *hapd);
#define for_each_mld_link(partner, self) \
dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link)

View file

@ -76,12 +76,15 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
int i, j;
unsigned int k;
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;
struct hostapd_multi_hw_info *multi_hw_info;
unsigned int num_multi_hws;
if (hostapd_drv_none(hapd))
return -1;
@ -168,6 +171,25 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
__func__);
}
multi_hw_info = hostapd_get_multi_hw_info(hapd, &num_multi_hws);
if (!multi_hw_info)
return 0;
hostapd_free_multi_hw_info(iface->multi_hw_info);
iface->multi_hw_info = multi_hw_info;
iface->num_multi_hws = num_multi_hws;
wpa_printf(MSG_DEBUG, "Multiple underlying hardwares info:");
for (k = 0; k < num_multi_hws; k++) {
struct hostapd_multi_hw_info *hw_info = &multi_hw_info[k];
wpa_printf(MSG_DEBUG,
" %d. hw_idx=%u, frequency range: %d-%d MHz",
k + 1, hw_info->hw_idx, hw_info->start_freq,
hw_info->end_freq);
}
return 0;
}
@ -1391,3 +1413,34 @@ int hostapd_hw_skip_mode(struct hostapd_iface *iface,
}
return 0;
}
void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info)
{
os_free(multi_hw_info);
}
int hostapd_set_current_hw_info(struct hostapd_iface *iface, int oper_freq)
{
struct hostapd_multi_hw_info *hw_info;
unsigned int i;
if (!iface->num_multi_hws)
return 0;
for (i = 0; i < iface->num_multi_hws; i++) {
hw_info = &iface->multi_hw_info[i];
if (hw_info->start_freq <= oper_freq &&
hw_info->end_freq >= oper_freq) {
iface->current_hw_info = hw_info;
wpa_printf(MSG_DEBUG,
"Mode: Selected underlying hardware: hw_idx=%u",
iface->current_hw_info->hw_idx);
return 0;
}
}
return -1;
}

View file

@ -30,6 +30,8 @@ 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);
void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info);
int hostapd_set_current_hw_info(struct hostapd_iface *iface, int oper_freq);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@ -103,6 +105,16 @@ static inline int hostapd_determine_mode(struct hostapd_iface *iface)
return 0;
}
static inline
void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info)
{
}
static inline int hostapd_set_current_hw_info(struct hostapd_iface *iface,
u32 oper_freq)
{
return 0;
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */

View file

@ -1173,16 +1173,23 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sae_data *sae = sta->sae;
int i, *groups = hapd->conf->sae_groups;
int default_groups[] = { 19, 0 };
struct hostapd_bss_config *conf = hapd->conf;
int i, *groups = conf->sae_groups;
int default_groups[] = { 19, 0, 0 };
if (sae->state != SAE_COMMITTED)
return;
wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
if (!groups)
if (!groups) {
groups = default_groups;
if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2))
default_groups[1] = 20;
}
for (i = 0; groups[i] > 0; i++) {
if (sae->group == groups[i])
break;
@ -1247,12 +1254,18 @@ static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
{
int *groups = hapd->conf->sae_groups;
int default_groups[] = { 19, 0 };
struct hostapd_bss_config *conf = hapd->conf;
int *groups = conf->sae_groups;
int default_groups[] = { 19, 0, 0 };
int i;
if (!groups)
if (!groups) {
groups = default_groups;
if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2))
default_groups[1] = 20;
}
for (i = 0; groups[i] > 0; i++) {
if (groups[i] == group)
@ -1309,14 +1322,20 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
{
int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
int *groups = hapd->conf->sae_groups;
int default_groups[] = { 19, 0 };
struct hostapd_bss_config *conf = hapd->conf;
int *groups = conf->sae_groups;
int default_groups[] = { 19, 0, 0 };
const u8 *pos, *end;
int sta_removed = 0;
bool success_status;
if (!groups)
if (!groups) {
groups = default_groups;
if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2))
default_groups[1] = 20;
}
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
@ -1609,12 +1628,12 @@ reply:
!data && end - pos >= 2)
data = wpabuf_alloc_copy(pos, 2);
sae_sme_send_external_auth_status(hapd, sta, resp);
send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
sae_sme_send_external_auth_status(hapd, sta, resp);
if (sta->sae && sta->sae->tmp && sta->sae->tmp->pw_id &&
resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER &&
auth_transaction == 1) {
@ -1935,6 +1954,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
goto fail;
}
wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
elems.rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
@ -2829,7 +2850,7 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
hapd_pasn_update_params(hapd, sta, mgmt, len);
if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
sta->addr, mgmt, len) < 0)
sta->addr, mgmt, len, false) < 0)
ap_free_sta(hapd, sta);
} else if (trans_seq == 3) {
if (!sta->pasn) {
@ -2874,7 +2895,7 @@ static void handle_auth(struct hostapd_data *hapd,
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
struct sta_info *sta = NULL;
int res, reply_res, ubus_resp;
int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
@ -2886,12 +2907,6 @@ static void handle_auth(struct hostapd_data *hapd,
bool mld_sta = false;
#endif /* CONFIG_IEEE80211BE */
struct hostapd_ubus_request req = {
.type = HOSTAPD_UBUS_AUTH_REQ,
.mgmt_frame = mgmt,
.ssi_signal = rssi,
};
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
(unsigned long) len);
@ -2967,7 +2982,10 @@ static void handle_auth(struct hostapd_data *hapd,
auth_alg == WLAN_AUTH_FT) ||
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
(hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
(hapd->conf->wpa &&
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
hapd->conf->rsn_override_key_mgmt |
hapd->conf->rsn_override_key_mgmt_2) &&
auth_alg == WLAN_AUTH_SAE) ||
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
@ -3008,14 +3026,6 @@ static void handle_auth(struct hostapd_data *hapd,
goto fail;
}
ubus_resp = hostapd_ubus_handle_event(hapd, &req);
if (ubus_resp) {
wpa_printf(MSG_DEBUG, "Station " MACSTR " rejected by ubus handler.\n",
MAC2STR(mgmt->sa));
resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
#ifdef CONFIG_IEEE80211BE
if (mld_sta &&
(ether_addr_equal(sa, hapd->own_addr) ||
@ -4142,6 +4152,8 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211BE */
wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
wpa_auth_set_rsn_selection(sta->wpa_sm, elems->rsn_selection,
elems->rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
@ -5002,7 +5014,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211AX */
p = hostapd_eid_ext_capab(hapd, p, false);
p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period);
p = hostapd_eid_bss_max_idle_period(hapd, p,
sta ? sta->max_idle_period : 0);
if (sta && sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
@ -5344,7 +5357,7 @@ static void handle_assoc(struct hostapd_data *hapd,
int resp = WLAN_STATUS_SUCCESS;
u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
int left, i, ubus_resp;
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
#ifdef CONFIG_FILS
@ -5587,12 +5600,6 @@ static void handle_assoc(struct hostapd_data *hapd,
}
#endif /* CONFIG_FILS */
struct hostapd_ubus_request req = {
.type = HOSTAPD_UBUS_ASSOC_REQ,
.mgmt_frame = mgmt,
.ssi_signal = rssi,
};
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@ -5694,14 +5701,6 @@ static void handle_assoc(struct hostapd_data *hapd,
if (set_beacon)
ieee802_11_update_beacons(hapd->iface);
ubus_resp = hostapd_ubus_handle_event(hapd, &req);
if (ubus_resp) {
wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n",
MAC2STR(mgmt->sa));
resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
fail:
/*
@ -5931,7 +5930,6 @@ static void handle_disassoc(struct hostapd_data *hapd,
(unsigned long) len);
return;
}
hostapd_ubus_notify(hapd, "disassoc", mgmt->sa);
sta = ap_get_sta(hapd, mgmt->sa);
if (!sta) {
@ -5960,8 +5958,6 @@ static void handle_deauth(struct hostapd_data *hapd,
return;
}
hostapd_ubus_notify(hapd, "deauth", mgmt->sa);
/* Clear the PTKSA cache entries for PASN */
ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
@ -7251,16 +7247,11 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
}
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
/* Wide Bandwidth Channel Switch subelement */
static u8 * hostapd_eid_wb_channel_switch(struct hostapd_data *hapd, u8 *eid,
u8 chan1, u8 chan2)
{
u8 bw, chan1 = 0, chan2 = 0;
int freq1;
if (!hapd->cs_freq_params.channel ||
(!hapd->cs_freq_params.vht_enabled &&
!hapd->cs_freq_params.he_enabled &&
!hapd->cs_freq_params.eht_enabled))
return eid;
u8 bw;
/* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per
* IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */
@ -7282,20 +7273,6 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
return eid;
}
freq1 = hapd->cs_freq_params.center_freq1 ?
hapd->cs_freq_params.center_freq1 :
hapd->cs_freq_params.freq;
if (ieee80211_freq_to_chan(freq1, &chan1) !=
HOSTAPD_MODE_IEEE80211A)
return eid;
if (hapd->cs_freq_params.center_freq2 &&
ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
&chan2) != HOSTAPD_MODE_IEEE80211A)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
*eid++ = 5; /* Length of Channel Switch Wrapper */
*eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
*eid++ = bw; /* New Channel Width */
@ -7321,6 +7298,118 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
}
#ifdef CONFIG_IEEE80211BE
/* Bandwidth Indication element that is also used as the Bandwidth Indication
* For Channel Switch subelement within a Channel Switch Wrapper element. */
static u8 * hostapd_eid_bw_indication(struct hostapd_data *hapd, u8 *eid,
u8 chan1, u8 chan2)
{
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
struct ieee80211_bw_ind_element *bw_ind_elem;
size_t elen = 3;
if (hapd->cs_freq_params.bandwidth <= 160 && !punct_bitmap)
return eid;
if (punct_bitmap)
elen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
*eid++ = WLAN_EID_EXTENSION;
*eid++ = 1 + elen;
*eid++ = WLAN_EID_EXT_BANDWIDTH_INDICATION;
bw_ind_elem = (struct ieee80211_bw_ind_element *) eid;
os_memset(bw_ind_elem, 0, sizeof(struct ieee80211_bw_ind_element));
switch (hapd->cs_freq_params.bandwidth) {
case 320:
bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_320MHZ;
chan2 = chan1;
if (hapd->cs_freq_params.channel < chan1)
chan1 -= 16;
else
chan1 += 16;
break;
case 160:
bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_160MHZ;
chan2 = chan1;
if (hapd->cs_freq_params.channel < chan1)
chan1 -= 8;
else
chan1 += 8;
break;
case 80:
bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_80MHZ;
break;
case 40:
if (hapd->cs_freq_params.sec_channel_offset == 1)
bw_ind_elem->bw_ind_info.control |=
BW_IND_CHANNEL_WIDTH_40MHZ;
else
bw_ind_elem->bw_ind_info.control |=
BW_IND_CHANNEL_WIDTH_20MHZ;
break;
default:
bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_20MHZ;
break;
}
bw_ind_elem->bw_ind_info.ccfs0 = chan1;
bw_ind_elem->bw_ind_info.ccfs1 = chan2;
if (punct_bitmap) {
bw_ind_elem->bw_ind_params |=
BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT;
bw_ind_elem->bw_ind_info.disabled_chan_bitmap =
host_to_le16(punct_bitmap);
}
return eid + elen;
}
#endif /* CONFIG_IEEE80211BE */
u8 * hostapd_eid_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
{
u8 chan1 = 0, chan2 = 0;
u8 *eid_len_offset;
int freq1;
if (!hapd->cs_freq_params.channel ||
(!hapd->cs_freq_params.vht_enabled &&
!hapd->cs_freq_params.he_enabled &&
!hapd->cs_freq_params.eht_enabled))
return eid;
freq1 = hapd->cs_freq_params.center_freq1 ?
hapd->cs_freq_params.center_freq1 :
hapd->cs_freq_params.freq;
if (ieee80211_freq_to_chan(freq1, &chan1) !=
HOSTAPD_MODE_IEEE80211A)
return eid;
if (hapd->cs_freq_params.center_freq2 &&
ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
&chan2) != HOSTAPD_MODE_IEEE80211A)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
eid_len_offset = eid++; /* Length of Channel Switch Wrapper element */
eid = hostapd_eid_wb_channel_switch(hapd, eid, chan1, chan2);
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
/* Bandwidth Indication For Channel Switch subelement */
eid = hostapd_eid_bw_indication(hapd, eid, chan1, chan2);
}
#endif /* CONFIG_IEEE80211BE */
*eid_len_offset = (eid - eid_len_offset) - 1;
return eid;
}
static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
size_t *current_len)
{

View file

@ -63,7 +63,7 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode);

View file

@ -871,6 +871,8 @@ sae_commit_skip_fixed_fields(const struct ieee80211_mgmt *mgmt, size_t len,
wpa_printf(MSG_DEBUG, "EHT: SAE scalar length is %zu", prime_len);
if (len - 2 < prime_len * (ec ? 3 : 2))
goto truncated;
/* scalar */
pos += prime_len;
@ -882,6 +884,7 @@ sae_commit_skip_fixed_fields(const struct ieee80211_mgmt *mgmt, size_t len,
}
if (pos - mgmt->u.auth.variable > (int) len) {
truncated:
wpa_printf(MSG_DEBUG,
"EHT: Too short SAE commit Authentication frame");
return NULL;
@ -905,16 +908,38 @@ sae_confirm_skip_fixed_fields(struct hostapd_data *hapd,
return pos;
/* send confirm integer */
if (len < 2)
goto truncated;
pos += 2;
/*
* At this stage we should already have an MLD station and actually SA
* will be replaced with the MLD MAC address by the driver.
* will be replaced with the MLD MAC address by the driver. However,
* there is at least a theoretical race condition in a case where the
* peer sends the SAE confirm message quickly enough for the driver
* translation mechanism to not be available to update the SAE confirm
* message addresses. Work around that by searching for the STA entry
* using the link address of the non-AP MLD if no match is found based
* on the MLD MAC address.
*/
sta = ap_get_sta(hapd, mgmt->sa);
if (!sta) {
wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm");
return NULL;
for (sta = hapd->sta_list; sta; sta = sta->next) {
int link_id = hapd->mld_link_id;
if (!sta->mld_info.mld_sta ||
sta->mld_info.links[link_id].valid ||
!ether_addr_equal(
mgmt->sa,
sta->mld_info.links[link_id].peer_addr))
continue;
wpa_printf(MSG_DEBUG,
"SAE: Found MLD STA for SAE confirm based on link address");
break;
}
if (!sta)
return NULL;
}
if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) {
@ -929,9 +954,12 @@ sae_confirm_skip_fixed_fields(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu",
sta->sae->tmp->kck_len);
if (len - 2 < sta->sae->tmp->kck_len)
goto truncated;
pos += sta->sae->tmp->kck_len;
if (pos - mgmt->u.auth.variable > (int) len) {
truncated:
wpa_printf(MSG_DEBUG,
"EHT: Too short SAE confirm Authentication frame");
return NULL;

View file

@ -79,6 +79,51 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
}
static void set_ht_param(struct hostapd_data *hapd,
struct ieee80211_ht_operation *oper)
{
int secondary_channel = hapd->iconf->secondary_channel;
#ifdef CONFIG_IEEE80211BE
enum oper_chan_width chwidth = hostapd_get_oper_chwidth(hapd->iconf);
u16 bw = 0, punct_bitmap = hostapd_get_punct_bitmap(hapd);
u8 offset, chan_bit_pos;
switch (chwidth) {
case CONF_OPER_CHWIDTH_80MHZ:
bw = 80;
offset = 6;
break;
case CONF_OPER_CHWIDTH_160MHZ:
bw = 160;
offset = 14;
break;
case CONF_OPER_CHWIDTH_320MHZ:
bw = 320;
offset = 30;
break;
default:
goto no_update;
}
chan_bit_pos = (hapd->iconf->channel -
hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf) +
offset) / 4;
/* Check if secondary channel is punctured */
if (bw >= 80 && punct_bitmap && secondary_channel &&
(punct_bitmap & BIT(chan_bit_pos + secondary_channel)))
return; /* Do not indicate punctured secondary channel for HT */
no_update:
#endif /* CONFIG_IEEE80211BE */
if (secondary_channel == 1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
if (secondary_channel == -1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
}
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_ht_operation *oper;
@ -96,12 +141,7 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
oper->primary_chan = hapd->iconf->channel;
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
if (hapd->iconf->secondary_channel == 1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
if (hapd->iconf->secondary_channel == -1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
set_ht_param(hapd, oper);
pos += sizeof(*oper);

View file

@ -158,7 +158,7 @@ int hostapd_nan_usd_init(struct hostapd_data *hapd)
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);
hapd->nan_de = nan_de_init(hapd->own_addr, false, true, &cb);
if (!hapd->nan_de)
return -1;
return 0;
@ -192,7 +192,7 @@ 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)
struct nan_publish_params *params, bool p2p)
{
int publish_id;
struct wpabuf *elems = NULL;
@ -201,7 +201,7 @@ int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
return -1;
publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
ssi, elems, params);
ssi, elems, params, p2p);
wpabuf_free(elems);
return publish_id;
}
@ -231,7 +231,7 @@ 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)
struct nan_subscribe_params *params, bool p2p)
{
int subscribe_id;
struct wpabuf *elems = NULL;
@ -240,7 +240,7 @@ int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
return -1;
subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
srv_proto_type, ssi, elems, params);
srv_proto_type, ssi, elems, params, p2p);
wpabuf_free(elems);
return subscribe_id;
}

View file

@ -21,7 +21,7 @@ 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);
struct nan_publish_params *params, bool p2p);
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);
@ -29,7 +29,7 @@ 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);
struct nan_subscribe_params *params, bool p2p);
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
int subscribe_id);
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,

View file

@ -89,9 +89,6 @@ static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
MAC2STR(addr), token, rep_mode, report);
if (len < sizeof(struct rrm_measurement_beacon_report))
return;
hostapd_ubus_notify_beacon_report(hapd, addr, token, rep_mode, (struct rrm_measurement_beacon_report*) pos, len);
}
@ -272,7 +269,6 @@ static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
}
}
hapd->liminix_stats.rrm.neighbor_report_tx++;
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@ -408,7 +404,6 @@ void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
hostapd_handle_nei_report_req(hapd, buf, len);
break;
case WLAN_RRM_LINK_MEASUREMENT_REPORT:
hostapd_ubus_handle_link_measurement(hapd, buf, len);
hostapd_handle_link_mesr_report(hapd, buf, len);
break;
default:

View file

@ -542,7 +542,6 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"local deauth request");
hostapd_ubus_notify(hapd, "local-deauth", sta->addr);
ap_free_sta(hapd, sta);
return;
}
@ -700,7 +699,6 @@ skip_poll:
mlme_deauthenticate_indication(
hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr);
ap_free_sta(hapd, sta);
break;
}
@ -1526,28 +1524,15 @@ void ap_sta_set_authorized_event(struct hostapd_data *hapd,
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
if (authorized) {
static const char * const auth_algs[] = {
[WLAN_AUTH_OPEN] = "open",
[WLAN_AUTH_SHARED_KEY] = "shared",
[WLAN_AUTH_FT] = "ft",
[WLAN_AUTH_SAE] = "sae",
[WLAN_AUTH_FILS_SK] = "fils-sk",
[WLAN_AUTH_FILS_SK_PFS] = "fils-sk-pfs",
[WLAN_AUTH_FILS_PK] = "fils-pk",
[WLAN_AUTH_PASN] = "pasn",
};
const char *auth_alg = NULL;
const u8 *dpp_pkhash;
const char *keyid;
char dpp_pkhash_buf[100];
char keyid_buf[100];
char ip_addr[100];
char alg_buf[100];
dpp_pkhash_buf[0] = '\0';
keyid_buf[0] = '\0';
ip_addr[0] = '\0';
alg_buf[0] = '\0';
#ifdef CONFIG_P2P
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
os_snprintf(ip_addr, sizeof(ip_addr),
@ -1558,13 +1543,6 @@ void ap_sta_set_authorized_event(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
if (sta->auth_alg < ARRAY_SIZE(auth_algs))
auth_alg = auth_algs[sta->auth_alg];
if (auth_alg)
os_snprintf(alg_buf, sizeof(alg_buf),
" auth_alg=%s", auth_alg);
keyid = ap_sta_wpa_get_keyid(hapd, sta);
if (keyid) {
os_snprintf(keyid_buf, sizeof(keyid_buf),
@ -1583,19 +1561,17 @@ void ap_sta_set_authorized_event(struct hostapd_data *hapd,
dpp_pkhash, SHA256_MAC_LEN);
}
hostapd_ubus_notify_authorized(hapd, sta, auth_alg);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s%s",
buf, ip_addr, keyid_buf, dpp_pkhash_buf, alg_buf);
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%s%s",
AP_STA_CONNECTED "%s%s%s%s",
buf, ip_addr, keyid_buf,
dpp_pkhash_buf, alg_buf);
dpp_pkhash_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
hostapd_ubus_notify(hapd, "disassoc", sta->addr);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)

View file

@ -81,20 +81,7 @@ struct mld_info {
u16 mld_capa;
} common_info;
struct mld_link_info {
u8 valid:1;
u8 nstr_bitmap_len:2;
u8 local_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN];
u8 nstr_bitmap[2];
u16 capability;
u16 status;
u16 resp_sta_profile_len;
u8 *resp_sta_profile;
} links[MAX_NUM_MLD_LINKS];
struct mld_link_info links[MAX_NUM_MLD_LINKS];
};
struct sta_info {
@ -321,7 +308,6 @@ struct sta_info {
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
unsigned int dyn_airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */

File diff suppressed because it is too large Load diff

View file

@ -1,162 +0,0 @@
/*
* hostapd / ubus support
* Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef __HOSTAPD_UBUS_H
#define __HOSTAPD_UBUS_H
#include "sta_info.h"
enum hostapd_ubus_event_type {
HOSTAPD_UBUS_PROBE_REQ,
HOSTAPD_UBUS_AUTH_REQ,
HOSTAPD_UBUS_ASSOC_REQ,
HOSTAPD_UBUS_TYPE_MAX
};
struct hostapd_ubus_request {
enum hostapd_ubus_event_type type;
const struct ieee80211_mgmt *mgmt_frame;
const struct ieee802_11_elems *elems;
int ssi_signal; /* dBm */
const u8 *addr;
};
struct hostapd_iface;
struct hostapd_data;
struct hapd_interfaces;
struct rrm_measurement_beacon_report;
struct sta_info;
#ifdef UBUS_SUPPORT
#include <libubox/avl.h>
#include <libubus.h>
struct hostapd_ubus_bss {
struct ubus_object obj;
struct avl_tree banned;
int notify_response;
};
void hostapd_ubus_add_iface(struct hostapd_iface *iface);
void hostapd_ubus_free_iface(struct hostapd_iface *iface);
void hostapd_ubus_add_bss(struct hostapd_data *hapd);
void hostapd_ubus_free_bss(struct hostapd_data *hapd);
void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
const u8 *addr, u8 token, u8 rep_mode,
struct rrm_measurement_beacon_report *rep,
size_t len);
void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2);
void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_add(struct hapd_interfaces *interfaces);
void hostapd_ubus_free(struct hapd_interfaces *interfaces);
int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
const char *auth_alg);
void hostapd_ubus_notify_readiness(struct hostapd_data *hapd);
#else
struct hostapd_ubus_bss {};
static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
{
}
static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
{
}
static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
{
}
static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
{
}
static inline void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
}
static inline void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
}
static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
{
return 0;
}
static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
{
}
static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
{
}
static inline void hostapd_ubus_notify_readiness(struct hostapd_data *hapd)
{
}
static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
const u8 *addr, u8 token,
u8 rep_mode,
struct rrm_measurement_beacon_report *rep,
size_t len)
{
}
static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2)
{
}
static inline void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len)
{
}
static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
{
}
static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
{
}
static inline int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len)
{
return 0;
}
static inline void
hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
const char *auth_alg)
{
}
#endif
#endif

View file

@ -22,7 +22,6 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
bool vlan_exists = iface_exists(vlan->ifname);
int ret;
#ifdef CONFIG_WEP
int i;
@ -37,7 +36,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
}
#endif /* CONFIG_WEP */
if (!vlan_exists)
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
else if (!existsok)
return -1;
@ -52,9 +51,6 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
if (hapd->wpa_auth)
ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
if (!ret && !vlan_exists)
hostapd_ubus_add_vlan(hapd, vlan);
if (ret == 0)
return ret;
@ -81,8 +77,6 @@ int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
"WPA deinitialization for VLAN %d failed (%d)",
vlan->vlan_id, ret);
hostapd_ubus_remove_vlan(hapd, vlan);
return hostapd_vlan_if_remove(hapd, vlan->ifname);
}

View file

@ -410,7 +410,6 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
pos = mgmt->u.action.u.bss_tm_req.variable;
hapd->liminix_stats.wnm.bss_transition_request_tx++;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
"validity_interval=%u",
@ -479,8 +478,7 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
MAC2STR(addr), reason, hex ? " neighbor=" : "", hex);
os_free(hex);
if (!hostapd_ubus_notify_bss_transition_query(hapd, addr, dialog_token, reason, pos, end - pos))
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
}
@ -502,7 +500,7 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
size_t len)
{
u8 dialog_token, status_code, bss_termination_delay;
const u8 *pos, *end, *target_bssid = NULL;
const u8 *pos, *end;
int enabled = hapd->conf->bss_transition;
struct sta_info *sta;
@ -549,7 +547,6 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
return;
}
target_bssid = pos;
sta->agreed_to_steer = 1;
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
@ -569,10 +566,6 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
MAC2STR(addr), status_code, bss_termination_delay);
}
hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token,
status_code, bss_termination_delay,
target_bssid, pos, end - pos);
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
@ -821,12 +814,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
plen);
return 0;
case WNM_BSS_TRANS_MGMT_QUERY:
hapd->liminix_stats.wnm.bss_transition_query_rx++;
ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
plen);
return 0;
case WNM_BSS_TRANS_MGMT_RESP:
hapd->liminix_stats.wnm.bss_transition_response_rx++;
ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
plen);
return 0;
@ -874,7 +865,6 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
pos = mgmt->u.action.u.bss_tm_req.variable;
hapd->liminix_stats.wnm.bss_transition_request_tx++;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
@ -957,7 +947,6 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
return -1;
}
hapd->liminix_stats.wnm.bss_transition_request_tx++;
if (disassoc_timer) {
/* send disassociation frame after time-out */
set_disassoc_timer(hapd, sta, disassoc_timer);
@ -1039,7 +1028,6 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
}
os_free(buf);
hapd->liminix_stats.wnm.bss_transition_request_tx++;
if (disassoc_timer) {
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {

View file

@ -112,10 +112,7 @@ static void wpa_gkeydone_sta(struct wpa_state_machine *sm)
int link_id;
#endif /* CONFIG_IEEE80211BE */
if (!sm->wpa_auth)
return;
sm->wpa_auth->group->GKeyDoneStations--;
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = false;
#ifdef CONFIG_IEEE80211BE
@ -1046,6 +1043,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
os_free(sm->rsn_selection);
#ifdef CONFIG_IEEE80211BE
for_each_sm_auth(sm, link_id) {
wpa_group_put(sm->mld_links[link_id].wpa_auth,
@ -1886,7 +1884,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
if (msg == PAIRWISE_2)
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
wpa_sm_step(sm);
out:
@ -2064,6 +2063,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (key_rsc)
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
#ifdef CONFIG_TESTING_OPTIONS
if (conf->eapol_key_reserved_random)
random_get_bytes(key->key_id, sizeof(key->key_id));
#endif /* CONFIG_TESTING_OPTIONS */
if (kde && !encr) {
os_memcpy(key_data, kde, kde_len);
WPA_PUT_BE16(key_mic + mic_len, kde_len);
@ -3914,6 +3918,34 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
goto out;
}
#endif /* CONFIG_IEEE80211R_AP */
/* Verify RSN Selection element for RSN overriding */
if ((wpa_auth->conf.rsn_override_key_mgmt ||
wpa_auth->conf.rsn_override_key_mgmt_2) &&
((rsn_is_snonce_cookie(sm->SNonce) && !kde.rsn_selection) ||
(!rsn_is_snonce_cookie(sm->SNonce) && kde.rsn_selection) ||
(sm->rsn_selection && !kde.rsn_selection) ||
(!sm->rsn_selection && kde.rsn_selection) ||
(sm->rsn_selection && kde.rsn_selection &&
(sm->rsn_selection_len != kde.rsn_selection_len ||
os_memcmp(sm->rsn_selection, kde.rsn_selection,
sm->rsn_selection_len) != 0)))) {
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
wpa_printf(MSG_DEBUG,
"SNonce cookie for RSN overriding %sused",
rsn_is_snonce_cookie(sm->SNonce) ? "" : "not ");
wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
sm->rsn_selection, sm->rsn_selection_len);
wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",
kde.rsn_selection, kde.rsn_selection_len);
/* MLME-DEAUTHENTICATE.request */
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
goto out;
}
#ifdef CONFIG_P2P
if (kde.ip_addr_req && kde.ip_addr_req[0] &&
wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
@ -4177,7 +4209,8 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot)
bool mgmt_frame_prot, bool beacon_prot,
bool rekey)
{
struct wpa_group *gsm = a->group;
u8 rsc[WPA_KEY_RSC_LEN];
@ -4190,7 +4223,7 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
info->gtk = gsm->GTK[gsm->GN - 1];
info->gtk_len = gsm->GTK_len;
if (wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0)
if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0)
os_memset(info->pn, 0, sizeof(info->pn));
else
os_memcpy(info->pn, rsc, sizeof(info->pn));
@ -4202,7 +4235,7 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
info->igtk = gsm->IGTK[gsm->GN_igtk - 4];
info->igtk_len = wpa_cipher_key_len(a->conf.group_mgmt_cipher);
if (wpa_auth_get_seqnum(a, NULL, gsm->GN_igtk, rsc) < 0)
if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN_igtk, rsc) < 0)
os_memset(info->ipn, 0, sizeof(info->ipn));
else
os_memcpy(info->ipn, rsc, sizeof(info->ipn));
@ -4218,7 +4251,7 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
info->bigtkidx = gsm->GN_bigtk;
info->bigtk = gsm->BIGTK[gsm->GN_bigtk - 6];
if (wpa_auth_get_seqnum(a, NULL, gsm->GN_bigtk, rsc) < 0)
if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN_bigtk, rsc) < 0)
os_memset(info->bipn, 0, sizeof(info->bipn));
else
os_memcpy(info->bipn, rsc, sizeof(info->bipn));
@ -4226,12 +4259,13 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth,
struct wpa_auth_ml_key_info *info)
struct wpa_auth_ml_key_info *info,
bool rekey)
{
if (!wpa_auth->cb->get_ml_key_info)
return;
wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info);
wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info, rekey);
}
@ -4288,6 +4322,7 @@ static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos)
struct wpa_auth_ml_key_info ml_key_info;
unsigned int i, link_id;
u8 *start = pos;
bool rekey = sm->wpa_ptk_group_state == WPA_PTK_GROUP_REKEYNEGOTIATING;
/* First fetch the key information from all the authenticators */
os_memset(&ml_key_info, 0, sizeof(ml_key_info));
@ -4307,7 +4342,7 @@ static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos)
ml_key_info.links[i++].link_id = link_id;
}
wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info);
wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey);
/* Add MLO GTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@ -4446,7 +4481,7 @@ static size_t wpa_auth_ml_kdes_len(struct wpa_state_machine *sm)
/* For the MAC Address KDE */
kde_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN;
/* MLO Link KDE for each link */
/* MLO Link KDE and RSN Override Link KDE for each link */
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct wpa_authenticator *wpa_auth;
const u8 *ie;
@ -4455,15 +4490,39 @@ static size_t wpa_auth_ml_kdes_len(struct wpa_state_machine *sm)
if (!wpa_auth)
continue;
/* MLO Link KDE */
kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN;
ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSN);
if (ie)
kde_len += 2 + ie[1];
ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSNX);
if (ie)
kde_len += 2 + ie[1];
if (!rsn_is_snonce_cookie(sm->SNonce))
continue;
/* RSN Override Link KDE */
kde_len += 2 + RSN_SELECTOR_LEN + 1;
ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNE_OVERRIDE_IE_VENDOR_TYPE);
if (ie)
kde_len += 2 + ie[1];
ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
if (ie)
kde_len += 2 + ie[1];
ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (ie)
kde_len += 2 + ie[1];
}
kde_len += wpa_auth_ml_group_kdes_len(sm);
@ -4488,8 +4547,9 @@ static u8 * wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos)
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct wpa_authenticator *wpa_auth;
const u8 *rsne, *rsnxe;
size_t rsne_len, rsnxe_len;
const u8 *rsne, *rsnxe, *rsnoe, *rsno2e, *rsnxoe;
size_t rsne_len, rsnxe_len, rsnoe_len, rsno2e_len, rsnxoe_len;
size_t kde_len;
wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
if (!wpa_auth)
@ -4508,6 +4568,7 @@ static u8 * wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos)
RSN_SELECTOR_LEN + 1 + ETH_ALEN +
rsne_len + rsnxe_len);
/* MLO Link KDE */
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = RSN_SELECTOR_LEN + 1 + ETH_ALEN +
rsne_len + rsnxe_len;
@ -4535,9 +4596,63 @@ static u8 * wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos)
os_memcpy(pos, rsnxe, rsnxe_len);
pos += rsnxe_len;
}
if (!rsn_is_snonce_cookie(sm->SNonce))
continue;
rsnoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNE_OVERRIDE_IE_VENDOR_TYPE);
rsnoe_len = rsnoe ? 2 + rsnoe[1] : 0;
rsno2e = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
rsno2e_len = rsno2e ? 2 + rsno2e[1] : 0;
rsnxoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
RSNXE_OVERRIDE_IE_VENDOR_TYPE);
rsnxoe_len = rsnxoe ? 2 + rsnxoe[1] : 0;
wpa_printf(MSG_DEBUG,
"RSN: RSN Override Link KDE: link=%u, len=%zu",
link_id, RSN_SELECTOR_LEN + rsnoe_len + rsno2e_len +
rsnxoe_len);
/* RSN Override Link KDE */
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
kde_len = RSN_SELECTOR_LEN + 1 + rsnoe_len + rsno2e_len +
rsnxoe_len;
if (kde_len > 255) {
wpa_printf(MSG_ERROR,
"RSN: RSNOE/RSNO2E/RSNXOE too long (KDE length %zu) to fit in RSN Override Link KDE for link %u",
kde_len, link_id);
return NULL;
}
*pos++ = kde_len;
RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_RSN_OVERRIDE_LINK);
pos += RSN_SELECTOR_LEN;
*pos++ = link_id;
if (rsnoe_len) {
os_memcpy(pos, rsnoe, rsnoe_len);
pos += rsnoe_len;
}
if (rsno2e_len) {
os_memcpy(pos, rsno2e, rsno2e_len);
pos += rsno2e_len;
}
if (rsnxoe_len) {
os_memcpy(pos, rsnxoe, rsnxoe_len);
pos += rsnxoe_len;
}
}
wpa_printf(MSG_DEBUG, "RSN: MLO Link KDE len = %ld", pos - start);
wpa_printf(MSG_DEBUG,
"RSN: MLO Link KDEs and RSN Override Link KDEs len = %ld",
pos - start);
pos = wpa_auth_ml_group_kdes(sm, pos);
#endif /* CONFIG_IEEE80211BE */
@ -4552,7 +4667,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int secure, gtkidx, encr = 0;
u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL, *wpa_ie_buf3 = NULL;
u8 hdr[2];
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
#ifdef CONFIG_IEEE80211BE
@ -4593,6 +4708,39 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
if ((conf->rsn_override_key_mgmt || conf->rsn_override_key_mgmt_2) &&
!rsn_is_snonce_cookie(sm->SNonce)) {
u8 *ie;
size_t ie_len;
u32 ids[] = {
RSNE_OVERRIDE_IE_VENDOR_TYPE,
RSNE_OVERRIDE_2_IE_VENDOR_TYPE,
RSNXE_OVERRIDE_IE_VENDOR_TYPE,
0
};
int i;
wpa_printf(MSG_DEBUG,
"RSN: Remove RSNE/RSNXE override elements");
wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs before edits",
wpa_ie, wpa_ie_len);
wpa_ie_buf3 = os_memdup(wpa_ie, wpa_ie_len);
if (!wpa_ie_buf3)
goto done;
wpa_ie = wpa_ie_buf3;
for (i = 0; ids[i]; i++) {
ie = (u8 *) get_vendor_ie(wpa_ie, wpa_ie_len, ids[i]);
if (ie) {
ie_len = 2 + ie[1];
os_memmove(ie, ie + ie_len,
wpa_ie_len - (ie + ie_len - wpa_ie));
wpa_ie_len -= ie_len;
}
}
wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs after edits",
wpa_ie, wpa_ie_len);
}
#ifdef CONFIG_TESTING_OPTIONS
if (conf->rsne_override_eapol_set) {
wpa_ie_buf2 = replace_ie(
@ -4832,6 +4980,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
#endif /* CONFIG_DPP2 */
pos = wpa_auth_ml_kdes(sm, pos);
if (!pos) {
wpa_printf(MSG_ERROR, "RSN: Failed to add MLO KDEs");
goto done;
}
if (sm->ssid_protection) {
*pos++ = WLAN_EID_SSID;
@ -4862,6 +5014,7 @@ done:
bin_clear_free(kde, kde_len);
os_free(wpa_ie_buf);
os_free(wpa_ie_buf2);
os_free(wpa_ie_buf3);
}
@ -5475,11 +5628,38 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
if (ctx != NULL && ctx != sm->group)
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
struct wpa_group *group = sm->group;
#ifdef CONFIG_IEEE80211BE
int link_id;
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
if (!sm->mld_links[link_id].valid)
continue;
if (sm->mld_links[link_id].wpa_auth &&
sm->mld_links[link_id].wpa_auth->group == ctx) {
group = sm->mld_links[link_id].wpa_auth->group;
wpa_auth = sm->mld_links[link_id].wpa_auth;
break;
}
}
#endif /* CONFIG_IEEE80211BE */
if (ctx && ctx != group)
return 0;
#ifdef CONFIG_IEEE80211BE
/* For ML STA, run rekey on the association link and send G1 with keys
* for all links. This is based on assumption that MLD level
* Authenticator updates group keys on all affiliated links in one shot
* and not independently or concurrently for separate links. */
if (sm->mld_assoc_link_id >= 0 &&
sm->mld_assoc_link_id != wpa_auth->link_id)
return 0;
#endif /* CONFIG_IEEE80211BE */
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
sm->GUpdateStationKeys = false;
@ -5491,7 +5671,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
* Since we clear the GKeyDoneStations before the loop, the
* station needs to be counted here anyway.
*/
wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"GUpdateStationKeys was already set when marking station for GTK rekeying");
}
@ -5501,6 +5681,11 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
return 0;
sm->group->GKeyDoneStations++;
#ifdef CONFIG_IEEE80211BE
for_each_sm_auth(sm, link_id)
sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations++;
#endif /* CONFIG_IEEE80211BE */
sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
@ -6813,6 +6998,30 @@ void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
}
void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
size_t len)
{
if (!sm)
return;
os_free(sm->rsn_selection);
sm->rsn_selection = NULL;
sm->rsn_selection_len = 0;
sm->rsn_override = false;
sm->rsn_override_2 = false;
if (ie) {
if (len >= 1) {
if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE)
sm->rsn_override = true;
else if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE_2)
sm->rsn_override_2 = true;
}
sm->rsn_selection = os_memdup(ie, len);
if (sm->rsn_selection)
sm->rsn_selection_len = len;
}
}
#ifdef CONFIG_DPP2
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
{

View file

@ -17,7 +17,7 @@
struct vlan_description;
struct mld_info;
#define MAX_OWN_IE_OVERRIDE 256
#define MAX_OWN_IE_OVERRIDE 257
#ifdef _MSC_VER
#pragma pack(push, 1)
@ -173,6 +173,8 @@ struct wpa_auth_config {
int wpa;
int extended_key_id;
int wpa_key_mgmt;
int rsn_override_key_mgmt;
int rsn_override_key_mgmt_2;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@ -184,6 +186,8 @@ struct wpa_auth_config {
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_override_pairwise;
int rsn_override_pairwise_2;
int rsn_preauth;
int eapol_version;
int wmm_enabled;
@ -192,6 +196,8 @@ struct wpa_auth_config {
int okc;
int tx_status;
enum mfp_options ieee80211w;
enum mfp_options rsn_override_mfp;
enum mfp_options rsn_override_mfp_2;
int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
@ -224,6 +230,21 @@ struct wpa_auth_config {
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
bool rsne_override_set;
u8 rsne_override[MAX_OWN_IE_OVERRIDE];
size_t rsne_override_len;
bool rsnoe_override_set;
u8 rsnoe_override[MAX_OWN_IE_OVERRIDE];
size_t rsnoe_override_len;
bool rsno2e_override_set;
u8 rsno2e_override[MAX_OWN_IE_OVERRIDE];
size_t rsno2e_override_len;
bool rsnxe_override_set;
u8 rsnxe_override[MAX_OWN_IE_OVERRIDE];
size_t rsnxe_override_len;
bool rsnxoe_override_set;
u8 rsnxoe_override[MAX_OWN_IE_OVERRIDE];
size_t rsnxoe_override_len;
u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
size_t rsne_override_eapol_len;
u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
@ -245,6 +266,7 @@ struct wpa_auth_config {
struct wpabuf *eapol_m1_elements;
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
bool eapol_key_reserved_random;
#endif /* CONFIG_TESTING_OPTIONS */
unsigned int oci_freq_override_eapol_m3;
unsigned int oci_freq_override_eapol_g1;
@ -295,6 +317,8 @@ struct wpa_auth_config {
#endif /* CONFIG_IEEE80211BE */
bool ssid_protection;
int rsn_override_omit_rsnxe;
};
typedef enum {
@ -400,7 +424,8 @@ struct wpa_auth_callbacks {
size_t ltf_keyseed_len);
#endif /* CONFIG_PASN */
#ifdef CONFIG_IEEE80211BE
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info,
bool rekey);
#endif /* CONFIG_IEEE80211BE */
int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
};
@ -605,6 +630,8 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
size_t len);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
@ -644,7 +671,8 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
u8 mld_assoc_link_id, struct mld_info *info);
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot);
bool mgmt_frame_prot, bool beacon_prot,
bool rekey);
void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
int release_link_id);

View file

@ -45,6 +45,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->wpa = conf->wpa;
wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->rsn_override_key_mgmt = conf->rsn_override_key_mgmt;
wconf->rsn_override_key_mgmt_2 = conf->rsn_override_key_mgmt_2;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
wconf->wpa_group_rekey = conf->wpa_group_rekey;
@ -56,6 +58,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
conf->wpa_disable_eapol_key_retries;
wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_override_pairwise = conf->rsn_override_pairwise;
wconf->rsn_override_pairwise_2 = conf->rsn_override_pairwise_2;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
#ifdef CONFIG_MACSEC
@ -70,6 +74,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
wconf->ieee80211w = conf->ieee80211w;
wconf->rsn_override_mfp = conf->rsn_override_mfp;
wconf->rsn_override_mfp_2 = conf->rsn_override_mfp_2;
wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
@ -126,6 +132,46 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
if (conf->rsne_override &&
wpabuf_len(conf->rsne_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsne_override_len = wpabuf_len(conf->rsne_override);
os_memcpy(wconf->rsne_override,
wpabuf_head(conf->rsne_override),
wconf->rsne_override_len);
wconf->rsne_override_set = true;
}
if (conf->rsnoe_override &&
wpabuf_len(conf->rsnoe_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsnoe_override_len = wpabuf_len(conf->rsnoe_override);
os_memcpy(wconf->rsnoe_override,
wpabuf_head(conf->rsnoe_override),
wconf->rsnoe_override_len);
wconf->rsnoe_override_set = true;
}
if (conf->rsno2e_override &&
wpabuf_len(conf->rsno2e_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsno2e_override_len = wpabuf_len(conf->rsno2e_override);
os_memcpy(wconf->rsno2e_override,
wpabuf_head(conf->rsno2e_override),
wconf->rsno2e_override_len);
wconf->rsno2e_override_set = true;
}
if (conf->rsnxe_override &&
wpabuf_len(conf->rsnxe_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsnxe_override_len = wpabuf_len(conf->rsnxe_override);
os_memcpy(wconf->rsnxe_override,
wpabuf_head(conf->rsnxe_override),
wconf->rsnxe_override_len);
wconf->rsnxe_override_set = true;
}
if (conf->rsnxoe_override &&
wpabuf_len(conf->rsnxoe_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsnxoe_override_len = wpabuf_len(conf->rsnxoe_override);
os_memcpy(wconf->rsnxoe_override,
wpabuf_head(conf->rsnxoe_override),
wconf->rsnxoe_override_len);
wconf->rsnxoe_override_set = true;
}
if (conf->rsne_override_eapol &&
wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsne_override_eapol_set = 1;
@ -190,6 +236,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
if (conf->eapol_m3_elements)
wconf->eapol_m3_elements = wpabuf_dup(conf->eapol_m3_elements);
wconf->eapol_m3_no_encrypt = conf->eapol_m3_no_encrypt;
wconf->eapol_key_reserved_random = conf->eapol_key_reserved_random;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@ -228,6 +275,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->no_disconnect_on_group_keyerror =
conf->bss_max_idle && conf->ap_max_inactivity &&
conf->no_disconnect_on_group_keyerror;
wconf->rsn_override_omit_rsnxe = conf->rsn_override_omit_rsnxe;
}
@ -279,7 +328,6 @@ static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
MAC2STR(addr));
hostapd_ubus_notify(hapd, "key-mismatch", addr);
}
@ -1539,7 +1587,8 @@ static int hostapd_set_ltf_keyseed(void *ctx, const u8 *peer_addr,
#ifdef CONFIG_IEEE80211BE
static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
struct wpa_auth_ml_key_info *info)
struct wpa_auth_ml_key_info *info,
bool rekey)
{
struct hostapd_data *hapd = ctx;
unsigned int i;
@ -1563,7 +1612,8 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
wpa_auth_ml_get_key_info(hapd->wpa_auth,
&info->links[i],
info->mgmt_frame_prot,
info->beacon_prot);
info->beacon_prot,
rekey);
continue;
}
@ -1574,7 +1624,8 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
wpa_auth_ml_get_key_info(bss->wpa_auth,
&info->links[i],
info->mgmt_frame_prot,
info->beacon_prot);
info->beacon_prot,
rekey);
link_bss_found = true;
break;
}

View file

@ -111,6 +111,8 @@ struct wpa_state_machine {
size_t wpa_ie_len;
u8 *rsnxe;
size_t rsnxe_len;
u8 *rsn_selection;
size_t rsn_selection_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@ -124,6 +126,9 @@ struct wpa_state_machine {
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
bool rsn_override;
bool rsn_override_2;
#ifdef CONFIG_IEEE80211R_AP
u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
* first 384 bits of MSK */

View file

@ -89,7 +89,8 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf,
enum mfp_options mfp)
{
u16 capab = 0;
@ -99,9 +100,9 @@ static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (mfp != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
if (mfp == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#ifdef CONFIG_OCV
@ -119,24 +120,19 @@ static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
}
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
static u8 * rsne_write_data(u8 *buf, size_t len, u8 *pos, int group,
int pairwise, int key_mgmt, u16 rsn_capab,
const u8 *pmkid, enum mfp_options mfp,
int group_mgmt_cipher)
{
struct rsn_ie_hdr *hdr;
int num_suites, res;
u8 *pos, *count;
u8 *count;
u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group);
if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", group);
return NULL;
}
RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
@ -153,7 +149,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#endif /* CONFIG_RSN_TESTING */
res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
res = rsn_cipher_put_suites(pos, pairwise);
num_suites += res;
pos += res * RSN_SELECTOR_LEN;
@ -167,8 +163,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->rsn_pairwise);
return -1;
pairwise);
return NULL;
}
WPA_PUT_LE16(count, num_suites);
@ -184,102 +180,102 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#endif /* CONFIG_RSN_TESTING */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
if (key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R_AP
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_SHA384
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SHA384 */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
if (key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SHA384
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SHA384 */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
if (key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
if (key_mgmt & WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SAE */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_FILS
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R_AP
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
@ -287,28 +283,28 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
#endif /* CONFIG_IEEE80211R_AP */
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
if (key_mgmt & WPA_KEY_MGMT_OWE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
if (key_mgmt & WPA_KEY_MGMT_DPP) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_DPP */
#ifdef CONFIG_HS20
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
if (key_mgmt & WPA_KEY_MGMT_OSEN) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_PASN
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
if (key_mgmt & WPA_KEY_MGMT_PASN) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
pos += RSN_SELECTOR_LEN;
num_suites++;
@ -325,18 +321,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
conf->wpa_key_mgmt);
return -1;
key_mgmt);
return NULL;
}
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
WPA_PUT_LE16(pos, rsn_capab);
pos += 2;
if (pmkid) {
if (2 + PMKID_LEN > buf + len - pos)
return -1;
return NULL;
/* PMKID Count */
WPA_PUT_LE16(pos, 1);
pos += 2;
@ -344,18 +340,19 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += PMKID_LEN;
}
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (mfp != NO_MGMT_FRAME_PROTECTION &&
group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
return -1;
if (pmkid == NULL) {
return NULL;
if (!pmkid) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
/* Management Group Cipher Suite */
switch (conf->group_mgmt_cipher) {
switch (group_mgmt_cipher) {
case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
break;
@ -371,8 +368,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
default:
wpa_printf(MSG_DEBUG,
"Invalid group management cipher (0x%x)",
conf->group_mgmt_cipher);
return -1;
group_mgmt_cipher);
return NULL;
}
pos += RSN_SELECTOR_LEN;
}
@ -384,12 +381,12 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
* the element.
*/
int pmkid_count_set = pmkid != NULL;
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
if (mfp != NO_MGMT_FRAME_PROTECTION)
pmkid_count_set = 1;
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
if (mfp == NO_MGMT_FRAME_PROTECTION) {
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
@ -399,6 +396,27 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
pos += 17;
}
#endif /* CONFIG_RSN_TESTING */
return pos;
}
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
u8 *pos;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
pos = rsne_write_data(buf, len, pos, conf->wpa_group,
conf->rsn_pairwise, conf->wpa_key_mgmt,
wpa_own_rsn_capab(conf, conf->ieee80211w), pmkid,
conf->ieee80211w, conf->group_mgmt_cipher);
if (!pos)
return -1;
hdr->len = (pos - buf) - 2;
@ -406,16 +424,74 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
static int wpa_write_rsne_override(struct wpa_auth_config *conf, u8 *buf,
size_t len)
{
u8 *pos = buf;
u32 capab = 0, tmp;
size_t flen;
u8 *pos, *len_pos;
if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
pos = buf;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
len_pos = pos++;
WPA_PUT_BE32(pos, RSNE_OVERRIDE_IE_VENDOR_TYPE);
pos += 4;
WPA_PUT_LE16(pos, RSN_VERSION);
pos += 2;
pos = rsne_write_data(buf, len, pos, conf->wpa_group,
conf->rsn_override_pairwise,
conf->rsn_override_key_mgmt,
wpa_own_rsn_capab(conf, conf->rsn_override_mfp),
NULL, conf->rsn_override_mfp,
conf->group_mgmt_cipher);
if (!pos)
return -1;
*len_pos = (pos - buf) - 2;
return pos - buf;
}
static int wpa_write_rsne_override_2(struct wpa_auth_config *conf, u8 *buf,
size_t len)
{
u8 *pos, *len_pos;
pos = buf;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
len_pos = pos++;
WPA_PUT_BE32(pos, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
pos += 4;
WPA_PUT_LE16(pos, RSN_VERSION);
pos += 2;
pos = rsne_write_data(buf, len, pos, conf->wpa_group,
conf->rsn_override_pairwise_2,
conf->rsn_override_key_mgmt_2,
wpa_own_rsn_capab(conf, conf->rsn_override_mfp_2),
NULL, conf->rsn_override_mfp_2,
conf->group_mgmt_cipher);
if (!pos)
return -1;
*len_pos = (pos - buf) - 2;
return pos - buf;
}
static u32 rsnxe_capab(struct wpa_auth_config *conf, int key_mgmt)
{
u32 capab = 0;
if (wpa_key_mgmt_sae(key_mgmt) &&
(conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
conf->sae_pwe == SAE_PWE_BOTH || conf->sae_pk ||
wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) {
wpa_key_mgmt_sae_ext_key(key_mgmt))) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (conf->sae_pk)
@ -432,6 +508,18 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
if (conf->ssid_protection)
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
return capab;
}
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
u32 capab = 0, tmp;
size_t flen;
capab = rsnxe_capab(conf, conf->wpa_key_mgmt);
if (!capab)
return 0; /* no supported extended RSN capabilities */
tmp = capab;
@ -455,6 +543,42 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
static int wpa_write_rsnxe_override(struct wpa_auth_config *conf, u8 *buf,
size_t len)
{
u8 *pos = buf;
u32 capab, tmp;
size_t flen;
capab = rsnxe_capab(conf, conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2);
if (!capab)
return 0; /* no supported extended RSN capabilities */
tmp = capab;
flen = 0;
while (tmp) {
flen++;
tmp >>= 8;
}
if (len < 2 + flen)
return -1;
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + flen;
WPA_PUT_BE32(pos, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
pos += 4;
while (capab) {
*pos++ = capab & 0xff;
capab >>= 8;
}
return pos - buf;
}
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
@ -508,7 +632,7 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
u8 *pos, buf[1500];
int res;
#ifdef CONFIG_TESTING_OPTIONS
@ -534,17 +658,54 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos = wpa_write_osen(&wpa_auth->conf, pos);
}
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.rsne_override_set) {
wpa_hexdump(MSG_DEBUG,
"RSN: Forced own RSNE for testing",
wpa_auth->conf.rsne_override,
wpa_auth->conf.rsne_override_len);
if (sizeof(buf) - (pos - buf) <
wpa_auth->conf.rsne_override_len)
return -1;
os_memcpy(pos, wpa_auth->conf.rsne_override,
wpa_auth->conf.rsne_override_len);
pos += wpa_auth->conf.rsne_override_len;
goto rsnxe;
}
#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
if (res < 0)
return res;
pos += res;
res = wpa_write_rsnxe(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
#ifdef CONFIG_TESTING_OPTIONS
rsnxe:
if (wpa_auth->conf.rsnxe_override_set) {
wpa_hexdump(MSG_DEBUG,
"RSN: Forced own RSNXE for testing",
wpa_auth->conf.rsnxe_override,
wpa_auth->conf.rsnxe_override_len);
if (sizeof(buf) - (pos - buf) <
wpa_auth->conf.rsnxe_override_len)
return -1;
os_memcpy(pos, wpa_auth->conf.rsnxe_override,
wpa_auth->conf.rsnxe_override_len);
pos += wpa_auth->conf.rsnxe_override_len;
goto fte;
}
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_auth->conf.rsn_override_omit_rsnxe)
res = 0;
else
res = wpa_write_rsnxe(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_TESTING_OPTIONS
fte:
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
@ -561,7 +722,87 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
return res;
pos += res;
}
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_auth->conf.rsn_override_key_mgmt) {
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.rsnoe_override_set) {
wpa_hexdump(MSG_DEBUG,
"RSN: Forced own RSNOE for testing",
wpa_auth->conf.rsnoe_override,
wpa_auth->conf.rsnoe_override_len);
if (sizeof(buf) - (pos - buf) <
wpa_auth->conf.rsnoe_override_len)
return -1;
os_memcpy(pos, wpa_auth->conf.rsnoe_override,
wpa_auth->conf.rsnoe_override_len);
pos += wpa_auth->conf.rsnoe_override_len;
goto rsno2e;
}
#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsne_override(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_TESTING_OPTIONS
rsno2e:
#endif /* CONFIG_TESTING_OPTIONS */
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_auth->conf.rsn_override_key_mgmt_2) {
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.rsno2e_override_set) {
wpa_hexdump(MSG_DEBUG,
"RSN: Forced own RSNO2E for testing",
wpa_auth->conf.rsno2e_override,
wpa_auth->conf.rsno2e_override_len);
if (sizeof(buf) - (pos - buf) <
wpa_auth->conf.rsno2e_override_len)
return -1;
os_memcpy(pos, wpa_auth->conf.rsno2e_override,
wpa_auth->conf.rsno2e_override_len);
pos += wpa_auth->conf.rsno2e_override_len;
goto rsnxoe;
}
#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsne_override_2(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_TESTING_OPTIONS
rsnxoe:
#endif /* CONFIG_TESTING_OPTIONS */
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
(wpa_auth->conf.rsn_override_key_mgmt ||
wpa_auth->conf.rsn_override_key_mgmt_2)) {
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.rsnxoe_override_set) {
wpa_hexdump(MSG_DEBUG,
"RSN: Forced own RSNXOE for testing",
wpa_auth->conf.rsnxoe_override,
wpa_auth->conf.rsnxoe_override_len);
if (sizeof(buf) - (pos - buf) <
wpa_auth->conf.rsnxoe_override_len)
return -1;
os_memcpy(pos, wpa_auth->conf.rsnxoe_override,
wpa_auth->conf.rsnxoe_override_len);
pos += wpa_auth->conf.rsnxoe_override_len;
goto done;
}
#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsnxe_override(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_TESTING_OPTIONS
done:
#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump(MSG_DEBUG, "RSN: Own IEs", buf, pos - buf);
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie = os_malloc(pos - buf);
if (wpa_auth->wpa_ie == NULL)
@ -773,7 +1014,13 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
return WPA_INVALID_GROUP;
}
key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (sm->rsn_override_2)
key_mgmt = data.key_mgmt &
wpa_auth->conf.rsn_override_key_mgmt_2;
else if (sm->rsn_override)
key_mgmt = data.key_mgmt & wpa_auth->conf.rsn_override_key_mgmt;
else
key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
@ -842,7 +1089,13 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
if (version == WPA_PROTO_RSN)
if (version == WPA_PROTO_RSN && sm->rsn_override_2)
ciphers = data.pairwise_cipher &
wpa_auth->conf.rsn_override_pairwise_2;
else if (version == WPA_PROTO_RSN && sm->rsn_override)
ciphers = data.pairwise_cipher &
wpa_auth->conf.rsn_override_pairwise;
else if (version == WPA_PROTO_RSN)
ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
@ -1229,7 +1482,7 @@ bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
return false;
/* RSN Capability (B0..B15) */
WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf, conf->ieee80211w));
pos += 2;
/* Group Data Cipher Suite Selector (B16..B21) */

View file

@ -83,13 +83,16 @@ _make_dirs:
@mkdir -p $(sort $(_DIRS))
$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
# for the fuzzing tests
$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
@echo $(CURDIR): '$(CC) -c -o $@ $(CFLAGS) $<' >$@.cmd
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<

View file

@ -532,4 +532,9 @@ enum sae_pwe {
SAE_PWE_NOT_SET = 4,
};
#define USEC_80211_TU 1024
#define USEC_TO_TU(m) ((m) / USEC_80211_TU)
#define TU_TO_USEC(m) ((m) * USEC_80211_TU)
#endif /* DEFS_H */

View file

@ -1035,6 +1035,10 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
json_value_sep(json);
json_add_string(json, "pkcs10", csr);
}
#ifdef CONFIG_DPP3
json_value_sep(json);
json_add_int(json, "capabilities", DPP_ENROLLEE_CAPAB_SAE_PW_ID);
#endif /* CONFIG_DPP3 */
if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
json_value_sep(json);
wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
@ -1139,8 +1143,18 @@ int dpp_configuration_valid(const struct dpp_configuration *conf)
return 0;
if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
return 0;
if (dpp_akm_psk(conf->akm) && conf->passphrase) {
size_t len = os_strlen(conf->passphrase);
if (len > 63 || len < 8)
return 0;
}
if (dpp_akm_sae(conf->akm) && !conf->passphrase)
return 0;
#ifdef CONFIG_DPP3
if (conf->idpass && (!conf->passphrase || !dpp_akm_sae(conf->akm)))
return 0;
#endif /* CONFIG_DPP3 */
return 1;
}
@ -1150,6 +1164,9 @@ void dpp_configuration_free(struct dpp_configuration *conf)
if (!conf)
return;
str_clear_free(conf->passphrase);
#ifdef CONFIG_DPP3
os_free(conf->idpass);
#endif /* CONFIG_DPP3 */
os_free(conf->group_id);
os_free(conf->csrattrs);
os_free(conf->extra_name);
@ -1228,14 +1245,28 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
end = os_strchr(pos, ' ');
pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
pass_len /= 2;
if (pass_len > 63 || pass_len < 8)
goto fail;
conf->passphrase = os_zalloc(pass_len + 1);
if (!conf->passphrase ||
hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
goto fail;
}
#ifdef CONFIG_DPP3
pos = os_strstr(cmd, " idpass=");
if (pos) {
size_t idpass_len;
pos += 8;
end = os_strchr(pos, ' ');
idpass_len = end ? (size_t) (end - pos) : os_strlen(pos);
idpass_len /= 2;
conf->idpass = os_zalloc(idpass_len + 1);
if (!conf->idpass ||
hexstr2bin(pos, (u8 *) conf->idpass, idpass_len) < 0)
goto fail;
}
#endif /* CONFIG_DPP3 */
pos = os_strstr(cmd, " psk=");
if (pos) {
pos += 5;
@ -1595,6 +1626,13 @@ static void dpp_build_legacy_cred_params(struct wpabuf *buf,
if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
json_add_string_escape(buf, "pass", conf->passphrase,
os_strlen(conf->passphrase));
#ifdef CONFIG_DPP3
if (conf->idpass) {
json_value_sep(buf);
json_add_string_escape(buf, "idpass", conf->idpass,
os_strlen(conf->idpass));
}
#endif /* CONFIG_DPP3 */
} else if (conf->psk_set) {
char psk[2 * sizeof(conf->psk) + 1];
@ -1917,6 +1955,16 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
const char *akm_str;
size_t len = 1000;
#ifdef CONFIG_DPP3
if (conf->idpass &&
!(auth->enrollee_capabilities & DPP_ENROLLEE_CAPAB_SAE_PW_ID)) {
wpa_printf(MSG_DEBUG,
"DPP: Enrollee does not support SAE Password Identifier - cannot generate config object");
return NULL;
}
#endif /* CONFIG_DPP3 */
if (conf->extra_name && conf->extra_value)
len += 10 + os_strlen(conf->extra_name) +
os_strlen(conf->extra_value);
@ -2535,6 +2583,18 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
cont:
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_DPP3
token = json_get_member(root, "capabilities");
if (token && token->type == JSON_NUMBER) {
wpa_printf(MSG_DEBUG, "DPP: capabilities = 0x%x",
token->number);
wpa_msg(auth->msg_ctx, MSG_INFO,
DPP_EVENT_ENROLLEE_CAPABILITY "%d",
token->number);
auth->enrollee_capabilities = token->number;
}
#endif /* CONFIG_DPP3 */
resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
cert_req);
@ -2558,13 +2618,25 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
if (pass && pass->type == JSON_STRING) {
size_t len = os_strlen(pass->string);
#ifdef CONFIG_DPP3
struct json_token *saepi = json_get_member(cred, "idpass");
#endif /* CONFIG_DPP3 */
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
pass->string, len);
if (len < 8 || len > 63)
if (dpp_akm_psk(conf->akm) && (len < 8 || len > 63)) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected pass length %zu for a config object that includes PSK",
len);
return -1;
}
os_strlcpy(conf->passphrase, pass->string,
sizeof(conf->passphrase));
#ifdef CONFIG_DPP3
if (saepi && saepi->type == JSON_STRING)
os_strlcpy(conf->password_id, saepi->string,
sizeof(conf->password_id));
#endif /* CONFIG_DPP3 */
} else if (psk_hex && psk_hex->type == JSON_STRING) {
if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
wpa_printf(MSG_DEBUG,

View file

@ -134,6 +134,9 @@ enum dpp_connector_key {
#define DPP_MAX_SHARED_SECRET_LEN 66
#define DPP_CP_LEN 64
/* DPP Configuration Request - Enrollee Capabilities */
#define DPP_ENROLLEE_CAPAB_SAE_PW_ID BIT(0)
struct dpp_curve_params {
const char *name;
size_t hash_len;
@ -260,6 +263,7 @@ struct dpp_configuration {
/* For legacy configuration */
char *passphrase;
char *idpass;
u8 psk[32];
int psk_set;
@ -356,6 +360,9 @@ struct dpp_authentication {
u8 ssid_len;
int ssid_charset;
char passphrase[64];
#ifdef CONFIG_DPP3
char password_id[64];
#endif /* CONFIG_DPP3 */
u8 psk[PMK_LEN];
int psk_set;
enum dpp_akm akm;
@ -393,6 +400,7 @@ struct dpp_authentication {
char *e_name;
char *e_mud_url;
int *e_band_support;
unsigned int enrollee_capabilities;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;

View file

@ -1033,3 +1033,18 @@ bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap)
return false;
}
bool chan_in_current_hw_info(struct hostapd_multi_hw_info *current_hw_info,
struct hostapd_channel_data *chan)
{
/* Assuming that if current_hw_info is not set full
* iface->current_mode->channels[] can be used to scan for channels,
* hence we return true.
*/
if (!current_hw_info)
return true;
return current_hw_info->start_freq <= chan->freq &&
current_hw_info->end_freq >= chan->freq;
}

View file

@ -58,5 +58,7 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
int ht40_plus, int pri);
int chan_pri_allowed(const struct hostapd_channel_data *chan);
bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap);
bool chan_in_current_hw_info(struct hostapd_multi_hw_info *current_hw_info,
struct hostapd_channel_data *chan);
#endif /* HW_FEATURES_COMMON_H */

View file

@ -140,6 +140,28 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->sae_pk = pos + 4;
elems->sae_pk_len = elen - 4;
break;
case WFA_RSNE_OVERRIDE_OUI_TYPE:
elems->rsne_override = pos;
elems->rsne_override_len = elen;
break;
case WFA_RSNE_OVERRIDE_2_OUI_TYPE:
elems->rsne_override_2 = pos;
elems->rsne_override_2_len = elen;
break;
case WFA_RSN_SELECTION_OUI_TYPE:
if (elen < 4 + 1) {
wpa_printf(MSG_DEBUG,
"Too short RSN Selection element ignored");
return -1;
}
elems->rsn_selection = pos + 4;
elems->rsn_selection_len = elen - 4;
break;
case P2P2_OUI_TYPE:
/* Wi-Fi Alliance - P2P2 IE */
elems->p2p2_ie = pos;
elems->p2p2_ie_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@ -3123,8 +3145,12 @@ bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len,
bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab)
{
return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL,
rsnxe ? rsnxe[1] : 0, capab);
if (!rsnxe)
return false;
if (rsnxe[0] == WLAN_EID_VENDOR_SPECIFIC && rsnxe[1] >= 4 + 1)
return ieee802_11_rsnx_capab_len(rsnxe + 2 + 4, rsnxe[1] - 4,
capab);
return ieee802_11_rsnx_capab_len(rsnxe + 2, rsnxe[1], capab);
}

View file

@ -65,6 +65,7 @@ struct ieee802_11_elems {
const u8 *vendor_ht_cap;
const u8 *vendor_vht;
const u8 *p2p;
const u8 *p2p2_ie;
const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
@ -116,6 +117,9 @@ struct ieee802_11_elems {
const u8 *prior_access_mle;
const u8 *mbssid_known_bss;
const u8 *mbssid;
const u8 *rsne_override;
const u8 *rsne_override_2;
const u8 *rsn_selection;
u8 ssid_len;
u8 supp_rates_len;
@ -136,6 +140,7 @@ struct ieee802_11_elems {
u8 vendor_ht_cap_len;
u8 vendor_vht_len;
u8 p2p_len;
u8 p2p2_ie_len;
u8 wfd_len;
u8 interworking_len;
u8 qos_map_set_len;
@ -179,6 +184,9 @@ struct ieee802_11_elems {
size_t prior_access_mle_len;
u8 mbssid_known_bss_len;
u8 mbssid_len;
size_t rsne_override_len;
size_t rsne_override_2_len;
size_t rsn_selection_len;
struct mb_ies_info mb_ies;

View file

@ -504,6 +504,7 @@
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52
#define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
#define WLAN_EID_EXT_NON_INHERITANCE 56
@ -524,6 +525,7 @@
#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
#define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
#define WLAN_EID_EXT_BANDWIDTH_INDICATION 135
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@ -1425,6 +1427,7 @@ struct ieee80211_ampe_ie {
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
#define P2P2_IE_VENDOR_TYPE 0x506f9a28
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
@ -1446,6 +1449,14 @@ struct ieee80211_ampe_ie {
#define QM_IE_OUI_TYPE 0x22
#define WFA_CAPA_IE_VENDOR_TYPE 0x506f9a23
#define WFA_CAPA_OUI_TYPE 0x23
#define WFA_RSNE_OVERRIDE_OUI_TYPE 0x29
#define WFA_RSNE_OVERRIDE_2_OUI_TYPE 0x2a
#define WFA_RSNXE_OVERRIDE_OUI_TYPE 0x2b
#define WFA_RSN_SELECTION_OUI_TYPE 0x2c
#define RSNE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a29
#define RSNE_OVERRIDE_2_IE_VENDOR_TYPE 0x506f9a2a
#define RSNXE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a2b
#define RSN_SELECTION_IE_VENDOR_TYPE 0x506f9a2c
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_PROFILE_SUB_ELEM_TYPE 0x07
@ -1710,6 +1721,7 @@ enum mbo_transition_reject_reason {
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
#define P2P2_OUI_TYPE 0x28
enum p2p_attr_id {
P2P_ATTR_STATUS = 0,
@ -1740,6 +1752,13 @@ enum p2p_attr_id {
P2P_ATTR_SESSION_ID = 26,
P2P_ATTR_FEATURE_CAPABILITY = 27,
P2P_ATTR_PERSISTENT_GROUP = 28,
P2P_ATTR_CAPABILITY_EXTENSION = 29,
P2P_ATTR_WLAN_AP_INFORMATION = 30,
P2P_ATTR_DEVICE_IDENTITY_KEY = 31,
P2P_ATTR_DEVICE_IDENTITY_RESOLUTION = 32,
P2P_ATTR_PAIRING_AND_BOOTSTRAPPING = 33,
P2P_ATTR_PASSWORD = 34,
P2P_ATTR_ACTION_FRAME_WRAPPER = 35,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
@ -1764,6 +1783,31 @@ enum p2p_attr_id {
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
/* P2P Capability Extension attribute - Capability info */
#define P2P_PCEA_LEN_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define P2P_PCEA_6GHZ BIT(4)
#define P2P_PCEA_REG_INFO BIT(5)
#define P2P_PCEA_DFS_OWNER BIT(6)
#define P2P_PCEA_CLI_REQ_CS BIT(7)
#define P2P_PCEA_PAIRING_CAPABLE BIT(8)
#define P2P_PCEA_PAIRING_SETUP_ENABLED BIT(9)
#define P2P_PCEA_PMK_CACHING BIT(10)
#define P2P_PCEA_PASN_TYPE BIT(11)
#define P2P_PCEA_TWT_POWER_MGMT BIT(12)
/* P2P Pairing Bootstrapping Method attribute - Bootstrapping Method */
#define P2P_PBMA_OPPORTUNISTIC BIT(0)
#define P2P_PBMA_PIN_CODE_DISPLAY BIT(1)
#define P2P_PBMA_PASSPHRASE_DISPLAY BIT(2)
#define P2P_PBMA_QR_DISPLAY BIT(3)
#define P2P_PBMA_NFC_TAG BIT(4)
#define P2P_PBMA_PIN_CODE_KEYPAD BIT(5)
#define P2P_PBMA_PASSPHRASE_KEYPAD BIT(6)
#define P2P_PBMA_QR_SCAN BIT(7)
#define P2P_PBMA_NFC_READER BIT(8)
#define P2P_PBMA_SERVICE_MANAGED BIT(14)
#define P2P_PBMA_HANDSHAKE_SKIP BIT(15)
/* P2PS Coordination Protocol Transport Bitmap */
#define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
@ -1795,6 +1839,7 @@ enum p2p_status_code {
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
P2P_SC_SUCCESS_DEFERRED = 12,
P2P_SC_COMEBACK = 13,
};
enum p2p_role_indication {
@ -2863,6 +2908,33 @@ enum ieee80211_eht_ml_sub_elem {
EHT_ML_SUB_ELEM_FRAGMENT = 254,
};
/* IEEE P802.11be/D7.0, 9.4.2.329 (Bandwidth Indication element) defines the
* Bandwidth Indication Information field to have the same definition as the
* EHT Operation Information field in the EHT Operation element.
*/
struct ieee80211_bw_ind_info {
u8 control; /* B0..B2: Channel Width */
u8 ccfs0;
u8 ccfs1;
le16 disabled_chan_bitmap; /* 0 or 2 octets */
} STRUCT_PACKED;
/* Control subfield: Channel Width subfield; see Table 9-417e (Channel width,
* CCFS0, and CCFS1 subfields) in IEEE P802.11be/D7.0. */
#define BW_IND_CHANNEL_WIDTH_20MHZ EHT_OPER_CHANNEL_WIDTH_20MHZ
#define BW_IND_CHANNEL_WIDTH_40MHZ EHT_OPER_CHANNEL_WIDTH_40MHZ
#define BW_IND_CHANNEL_WIDTH_80MHZ EHT_OPER_CHANNEL_WIDTH_80MHZ
#define BW_IND_CHANNEL_WIDTH_160MHZ EHT_OPER_CHANNEL_WIDTH_160MHZ
#define BW_IND_CHANNEL_WIDTH_320MHZ EHT_OPER_CHANNEL_WIDTH_320MHZ
/* IEEE P802.11be/D7.0, 9.4.2.329 (Bandwidth Indication element) */
struct ieee80211_bw_ind_element {
u8 bw_ind_params; /* Bandwidth Indication Parameters */
struct ieee80211_bw_ind_info bw_ind_info; /* 3 or 5 octets */
} STRUCT_PACKED;
#define BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7

View file

@ -58,10 +58,12 @@ struct nan_de_service {
struct os_reltime next_publish_state;
struct os_reltime next_publish_chan;
unsigned int next_publish_duration;
bool is_p2p;
};
struct nan_de {
u8 nmi[ETH_ALEN];
bool offload;
bool ap;
struct nan_callbacks cb;
@ -77,7 +79,7 @@ struct nan_de {
};
struct nan_de * nan_de_init(const u8 *nmi, bool ap,
struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
const struct nan_callbacks *cb)
{
struct nan_de *de;
@ -87,6 +89,7 @@ struct nan_de * nan_de_init(const u8 *nmi, bool ap,
return NULL;
os_memcpy(de->nmi, nmi, ETH_ALEN);
de->offload = offload;
de->ap = ap;
os_memcpy(&de->cb, cb, sizeof(*cb));
@ -590,7 +593,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
if (srv_next >= 0 && (next == -1 || srv_next < next))
next = srv_next;
if (srv_next == 0 && !started &&
if (srv_next == 0 && !started && !de->offload &&
de->listen_freq == 0 && de->ext_listen_freq == 0 &&
de->tx_wait_end_freq == 0 &&
nan_de_next_multicast(de, srv, &now) == 0) {
@ -598,7 +601,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
nan_de_tx_multicast(de, srv, 0);
}
if (!started && de->cb.listen &&
if (!started && !de->offload && de->cb.listen &&
de->listen_freq == 0 && de->ext_listen_freq == 0 &&
de->tx_wait_end_freq == 0 &&
((srv->type == NAN_DE_PUBLISH &&
@ -774,6 +777,34 @@ static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id,
}
static void nan_de_process_elem_container(struct nan_de *de, const u8 *buf,
size_t len, const u8 *peer_addr,
unsigned int freq, bool p2p)
{
const u8 *elem;
u16 elem_len;
elem = nan_de_get_attr(buf, len, NAN_ATTR_ELEM_CONTAINER, 0);
if (!elem)
return;
elem++;
elem_len = WPA_GET_LE16(elem);
elem += 2;
/* Skip the attribute if there is not enough froom for an element. */
if (elem_len < 1 + 2)
return;
/* Skip Map ID */
elem++;
elem_len--;
if (p2p && de->cb.process_p2p_usd_elems)
de->cb.process_p2p_usd_elems(de->cb.ctx, elem, elem_len,
peer_addr, freq);
}
static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
const u8 *peer_addr, u8 instance_id,
u8 req_instance_id, u16 sdea_control,
@ -787,13 +818,13 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
nan_de_run_timer(de);
}
if (srv->subscribe.active && req_instance_id == 0) {
if (!de->offload && srv->subscribe.active && req_instance_id == 0) {
/* Active subscriber replies with a Subscribe message if it
* received a matching unsolicited Publish message. */
nan_de_tx_multicast(de, srv, instance_id);
}
if (!srv->subscribe.active && req_instance_id == 0) {
if (!de->offload && !srv->subscribe.active && req_instance_id == 0) {
/* Passive subscriber replies with a Follow-up message without
* Service Specific Info field if it received a matching
* unsolicited Publish message. */
@ -873,6 +904,9 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
return;
}
if (de->offload)
goto offload;
/* Reply with a solicited Publish message */
/* Service Descriptor attribute */
sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1;
@ -939,6 +973,7 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
nan_de_pause_state(srv, peer_addr, instance_id);
offload:
if (!srv->publish.disable_events && de->cb.replied)
de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id,
srv_proto_type, ssi, ssi_len);
@ -1094,6 +1129,8 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
wpa_hexdump(MSG_MSGDUMP, "NAN: ssi",
ssi, ssi_len);
}
nan_de_process_elem_container(de, buf, len, peer_addr,
freq, srv->is_p2p);
}
switch (type) {
@ -1196,10 +1233,23 @@ static int nan_de_derive_service_id(struct nan_de_service *srv)
}
const u8 * nan_de_get_service_id(struct nan_de *de, int id)
{
struct nan_de_service *srv;
if (id < 1 || id > NAN_DE_MAX_SERVICE)
return NULL;
srv = de->service[id - 1];
if (!srv)
return NULL;
return srv->service_id;
}
int nan_de_publish(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
struct nan_publish_params *params)
struct nan_publish_params *params, bool p2p)
{
int publish_id;
struct nan_de_service *srv;
@ -1261,6 +1311,7 @@ int nan_de_publish(struct nan_de *de, const char *service_name,
wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s",
publish_id, service_name);
srv->id = publish_id;
srv->is_p2p = p2p;
nan_de_add_srv(de, srv);
nan_de_run_timer(de);
return publish_id;
@ -1312,7 +1363,7 @@ int nan_de_update_publish(struct nan_de *de, int publish_id,
int nan_de_subscribe(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
struct nan_subscribe_params *params)
struct nan_subscribe_params *params, bool p2p)
{
int subscribe_id;
struct nan_de_service *srv;
@ -1337,6 +1388,17 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name,
if (nan_de_derive_service_id(srv) < 0)
goto fail;
os_memcpy(&srv->subscribe, params, sizeof(*params));
if (params->freq_list) {
size_t len;
len = (int_array_len(params->freq_list) + 1) * sizeof(int);
srv->freq_list = os_memdup(params->freq_list, len);
if (!srv->freq_list)
goto fail;
}
srv->subscribe.freq_list = NULL;
srv->srv_proto_type = srv_proto_type;
if (ssi) {
srv->ssi = wpabuf_dup(ssi);
@ -1352,6 +1414,7 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name,
wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s",
subscribe_id, service_name);
srv->id = subscribe_id;
srv->is_p2p = p2p;
nan_de_add_srv(de, srv);
nan_de_run_timer(de);
return subscribe_id;

View file

@ -53,9 +53,13 @@ struct nan_callbacks {
void (*receive)(void *ctx, int id, int peer_instance_id,
const u8 *ssi, size_t ssi_len,
const u8 *peer_addr);
void (*process_p2p_usd_elems)(void *ctx, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
unsigned int freq);
};
struct nan_de * nan_de_init(const u8 *nmi, bool ap,
struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
const struct nan_callbacks *cb);
void nan_de_flush(struct nan_de *de);
void nan_de_deinit(struct nan_de *de);
@ -68,6 +72,7 @@ void nan_de_tx_wait_ended(struct nan_de *de);
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
const u8 *buf, size_t len);
const u8 * nan_de_get_service_id(struct nan_de *de, int id);
struct nan_publish_params {
/* configuration_parameters */
@ -105,7 +110,7 @@ struct nan_publish_params {
int nan_de_publish(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
struct nan_publish_params *params);
struct nan_publish_params *params, bool p2p);
void nan_de_cancel_publish(struct nan_de *de, int publish_id);
@ -124,6 +129,9 @@ struct nan_subscribe_params {
/* Selected frequency */
unsigned int freq;
/* Multi-channel frequencies (publishChannelList) */
const int *freq_list;
/* Query period in ms; 0 = use default */
unsigned int query_period;
};
@ -132,7 +140,7 @@ struct nan_subscribe_params {
int nan_de_subscribe(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
struct nan_subscribe_params *params);
struct nan_subscribe_params *params, bool p2p);
void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id);

View file

@ -230,7 +230,8 @@ enum qca_radiotap_vendor_ids {
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
* the possible features.
* the possible features that are encoded in
* QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS.
*
* @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver,
* which supports DFS offloading, to indicate a channel availability check
@ -1132,6 +1133,39 @@ enum qca_radiotap_vendor_ids {
* Uses the attributes defined in
* enum qca_wlan_vendor_attr_tdls_disc_rsp_ext.
*
* @QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH: This vendor subcommand is
* used to configure and indicate the audio transport switch in both
* command and event paths. This is used when two or more audio transports
* (e.g., WLAN and Bluetooth) are available between peers.
*
* If the driver needs to perform operations like scan, connection,
* roaming, RoC, etc. and AP concurrency policy is set to either
* QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO or
* QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING, the driver sends
* audio transport switch event to userspace. Userspace application upon
* receiving the event, can try to switch to the requested audio transport.
* The userspace uses this command to send the status of transport
* switching (either confirm or reject) to the driver using this
* subcommand. The driver continues with the pending operation either upon
* receiving the command from userspace or after waiting for a timeout from
* sending the event to userspace. The driver can request userspace to
* switch to WLAN upon availability of WLAN audio transport once after the
* concurrent operations are completed.
*
* Userspace can also request audio transport switch from non-WLAN to WLAN
* using this subcommand to the driver. The driver can accept or reject
* depending on other concurrent operations in progress. The driver returns
* success if it can allow audio transport when it receives the command or
* appropriate kernel error code otherwise. Userspace indicates the audio
* transport switch from WLAN to non-WLAN using this subcommand and the
* driver can do other concurrent operations without needing to send any
* event to userspace. This subcommand is used by userspace only when the
* driver advertises support for
* QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN.
*
* The attributes used with this command are defined in enum
* qca_wlan_vendor_attr_audio_transport_switch.
*
* @QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY: This vendor subcommand is used to
* configure, retrieve, and report per-link transmit latency statistics.
*
@ -1227,6 +1261,35 @@ enum qca_radiotap_vendor_ids {
* collection of these statistics has been enabled by the command
* @QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY. The attributes for this
* event are defined in enum qca_wlan_vendor_attr_flow_stats.
*
* @QCA_NL80211_VENDOR_SUBCMD_USD: Vendor subcommand to implement unsynchronized
* service discovery (USD). Based on the type of the USD subcommand the USD
* operation to publish, subscribe, update publish, cancel publish, or
* cancel subscribe is triggered.
*
* When used as an event, the driver notifies the status of an USD command.
*
* The attributes used with this command are defined in
* enum qca_wlan_vendor_attr_usd.
*
* @QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT: This is an extension to
* %NL80211_CMD_CONNECT command. Userspace can use this to indicate
* additional information to be considered for the subsequent
* (re)association request attempts with %NL80211_CMD_CONNECT. The
* additional information sent with this command is applicable for the
* entire duration of the connection established with %NL80211_CMD_CONNECT,
* including the roams triggered by the driver internally due to other
* vendor interfaces, driver internal logic, and BTM requests from the
* connected AP.
*
* @QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE: Vendor subcommand to configure
* Wi-Fi Direct mode. This command sets the configuration through
* the attributes defined in the enum qca_wlan_vendor_attr_set_p2p_mode.
* It is applicable for P2P Group Owner only. This command is used before
* starting the GO.
*
* The attributes used with this command are defined in
* enum qca_wlan_vendor_attr_connect_ext.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@ -1442,7 +1505,7 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP = 229,
QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG = 230,
QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT = 231,
/* 232 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH = 232,
QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY = 233,
/* 234 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SDWF_PHY_OPS = 235,
@ -1459,6 +1522,9 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_FLOW_CLASSIFY_RESULT = 246,
QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY = 247,
QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT = 248,
QCA_NL80211_VENDOR_SUBCMD_USD = 249,
QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT = 250,
QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE = 251,
};
/* Compatibility defines for previously used subcmd names.
@ -1485,7 +1551,11 @@ enum qca_wlan_vendor_attr {
*/
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
/* Feature flags contained in a byte array. The feature flags are
* identified by their bit index (see &enum qca_wlan_vendor_features)
* with the first byte being the least significant one and the last one
* being the most significant one. Used by
* QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES. */
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
QCA_WLAN_VENDOR_ATTR_TEST = 8,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
@ -2180,6 +2250,15 @@ enum qca_wlan_vendor_acs_hw_mode {
* that the device supports enhanced audio experience over WLAN feature.
* @QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER: Flag indicates that the device
* in AP mode supports TWT responder mode in HT and VHT modes.
*
* @QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA: Flag indicates that the device
* supports RSNE/RSNXE overriding in STA mode. Supplicant should enable
* RSN overriding elements use only when the driver indicates this feature
* flag. For BSS selection offload to the driver case, the driver shall
* strip/modify the RSN Selection element indicated in connect request
* elements or add that element if none was provided based on the BSS
* selected by the driver.
*
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@ -2208,6 +2287,7 @@ enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST = 22,
QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN = 23,
QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER = 24,
QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA = 25,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@ -2627,6 +2707,9 @@ enum qca_wlan_vendor_scan_priority {
* when AP is operating as MLD to specify which link is requesting the
* scan or which link the scan result is for. No need of this attribute
* in other cases.
* @QCA_WLAN_VENDOR_ATTR_SCAN_SKIP_CHANNEL_RECENCY_PERIOD: Optional (u32). Skip
* scanning channels which are scanned recently within configured time
* (in ms).
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@ -2645,6 +2728,7 @@ enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY = 13,
QCA_WLAN_VENDOR_ATTR_SCAN_PAD = 14,
QCA_WLAN_VENDOR_ATTR_SCAN_LINK_ID = 15,
QCA_WLAN_VENDOR_ATTR_SCAN_SKIP_CHANNEL_RECENCY_PERIOD = 16,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@ -3646,6 +3730,17 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_FOLLOW_AP_PREFERENCE_FOR_CNDS_SELECT = 121,
/* 16-bit unsigned value to configure P2P GO beacon interval in TUs.
* This attribute is used to update the P2P GO beacon interval
* dynamically.
*
* Updating the beacon interval while the GO continues operating the BSS
* will likely interoperability issues and is not recommended to be
* used. All the values should be multiples of the minimum used value to
* minimize risk of issues.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_P2P_GO_BEACON_INTERVAL = 122,
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@ -7417,6 +7512,10 @@ enum qca_wlan_vendor_attr_external_acs_event {
* for External ACS
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15,
/* Link ID attibute (u8) is used to identify a specific link affiliated
* to an AP MLD.
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LINK_ID = 16,
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@ -10358,6 +10457,14 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_SCS_TRAFFIC_SUPPORT = 73,
/* 8-bit unsigned value to disable or not disable the channel switch
* initiation in P2P GO mode.
* 0 - Not-disable, 1 - Disable
*
* This attribute is used for testing purposes.
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_CHAN_SWITCH_INITIATION = 74,
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@ -12411,6 +12518,12 @@ enum qca_wlan_vendor_attr_add_sta_node_params {
*/
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_IS_ML = 3,
/*
* This is u8 attribute used to identify a specific link affiliated
* to an AP MLD.
*/
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_LINK_ID = 4,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
@ -17849,4 +17962,318 @@ enum qca_wlan_intf_offload_type {
QCA_WLAN_INTF_OFFLOAD_TYPE_PPE_DS = 3,
};
/**
* enum qca_wlan_vendor_attr_usd_op_type: Attribute values for
* %QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE to the vendor subcmd
* %QCA_NL80211_VENDOR_SUBCMD_USD. This is a mandatory u8 attribute which
* represents the USD command type.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_FLUSH: Indicates USD tear down of all active
* publish and subscribe sessions.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH: Indicates USD solicited publish
* operation that enables to offer a service for other devices based on
* given parameters.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE: Indicates USD active subscribe
* operation that requests for a given service with given parameters from
* other devices that offer the service.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_UPDATE_PUBLISH: Indicates update of an instance
* of the publish function of given publish id.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_PUBLISH: Indicates cancellation of an
* instance of the publish function.
*
* @QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_SUBSCRIBE: Indicates cancellation of an
* instance of the subscribe function.
*/
enum qca_wlan_vendor_attr_an_usd_op_type {
QCA_WLAN_VENDOR_USD_OP_TYPE_FLUSH = 0,
QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH = 1,
QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE = 2,
QCA_WLAN_VENDOR_USD_OP_TYPE_UPDATE_PUBLISH = 3,
QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_PUBLISH = 4,
QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_SUBSCRIBE = 5,
};
/**
* enum qca_wlan_vendor_attr_usd_service_protocol_type: Attribute values for
* %QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE to the vendor subcmd
* %QCA_NL80211_VENDOR_SUBCMD_USD. This is a u8 attribute which represents the
* USD service protocol type for service specific information.
*
* @QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_BONJOUR: Indicates SSI info is
* of type Bonjour
* @QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_GENERIC: Indicates SSI info is
* of type generic
* @QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_CSA_MATTER: Indicates SSI info
* is of type CSA/Matter
*/
enum qca_wlan_vendor_attr_usd_service_protocol_type {
QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_BONJOUR = 1,
QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_GENERIC = 2,
QCA_WLAN_VENDOR_USD_SERVICE_PROTOCOL_TYPE_CSA_MATTER = 3,
};
/**
* enum qca_wlan_vendor_attr_usd_chan_config - Attributes used inside nested
* attribute %QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG.
*
* @QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ: Required
* u32 attribute containing the default channel frequency (MHz).
*
* @QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST: Optional array of channel
* frequencies in MHz (u32) to publish or subscribe.
*/
enum qca_wlan_vendor_attr_usd_chan_config {
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ = 1,
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST = 2,
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_MAX =
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_AFTER_LAST - 1,
};
/**
* enum qca_wlan_vendor_attr_usd_status
*
* @QCA_WLAN_VENDOR_ATTR_USD_STATUS_SUCCESS: USD request success status.
* @QCA_WLAN_VENDOR_ATTR_USD_STATUS_FAILED: USD request failed status.
*/
enum qca_wlan_vendor_attr_usd_status {
QCA_WLAN_VENDOR_ATTR_USD_STATUS_SUCCESS,
QCA_WLAN_VENDOR_ATTR_USD_STATUS_FAILED,
};
/* enum qca_wlan_vendor_attr_usd: Attributes used by vendor command
* %QCA_NL80211_VENDOR_SUBCMD_USD.
*
* @QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR: 6-byte source MAC address
* Mandatory attribute used with type
* %QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH and
* %QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE.
*
* @QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE: Required u8 attribute.
* It indicates the type of the USD command. It uses values defined in enum
* qca_wlan_vendor_attr_usd_op_type.
*
* @QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID: Required u8 attribute.
* It contains the publisher/subscribe id that is specific to the
* publish/subscribe instance.
*
* @QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID: Required 6-byte attribute.
* It contains the service id that is specific to the service being
* published/subscribed.
*
* @QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE: u8 attribute that indicates
* the service protocol type of service specific info. It uses values
* defined in enum qca_wlan_vendor_attr_usd_service_protocol_type. It is
* applicable when %QCA_WLAN_VENDOR_ATTR_USD_SSI is present.
*
* @QCA_WLAN_VENDOR_ATTR_USD_SSI: u8 array containing service specific
* information that has to be conveyed in publish/subscribe message.
* Optional attribute used with type
* %QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH,
* %QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE, and
* %QCA_WLAN_VENDOR_USD_OP_TYPE_UPDATE_PUBLISH.
*
* @QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG: Nested attribute containing USD
* channel configuration parameters.
* Required for type %QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH and
* %QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE.
* See enum qca_wlan_vendor_attr_usd_chan_config for nested attributes.
*
* @QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER: u8 array containing a USD
* element container buffer that has to be conveyed in publish/subscribe
* message.
* Required for type %QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH and
* %QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE.
*
* @QCA_WLAN_VENDOR_ATTR_USD_TTL: u16 attribute. Indicates the timeout
* for each request in seconds. Timeout value 0 represents single time
* operation.
*
* @QCA_WLAN_VENDOR_ATTR_USD_STATUS: u8 attribute. Status received in event
* indicating whether the underlying driver/firmware has started the USD
* operation as indicated by attributes
* %QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE and
* %QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID.
* enum qca_wlan_vendor_attr_usd_status indicates status values.
*/
enum qca_wlan_vendor_attr_usd {
QCA_WLAN_VENDOR_ATTR_USD_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR = 1,
QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE = 2,
QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID = 3,
QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID = 4,
QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE = 5,
QCA_WLAN_VENDOR_ATTR_USD_SSI = 6,
QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG = 7,
QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER = 8,
QCA_WLAN_VENDOR_ATTR_USD_TTL = 9,
QCA_WLAN_VENDOR_ATTR_USD_STATUS = 10,
QCA_WLAN_VENDOR_ATTR_USD_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_USD_MAX =
QCA_WLAN_VENDOR_ATTR_USD_AFTER_LAST - 1,
};
/**
* enum qca_wlan_audio_transport_switch_type - Represents the possible transport
* switch types.
*
* @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN: Request to route audio data
* via non-WLAN transport (e.g., Bluetooth).
*
* @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN: Request to route audio data via
* WLAN transport.
*/
enum qca_wlan_audio_transport_switch_type {
QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN = 0,
QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN = 1,
};
/**
* enum qca_wlan_audio_transport_switch_status - Represents the status of audio
* transport switch request.
*
* @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED: Request to switch transport
* has been rejected. For example, when transport switch is requested from WLAN
* to non-WLAN transport, user space modules and peers would evaluate the switch
* request and may not be ready for switch and hence switch to non-WLAN
* transport gets rejected.
*
* @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED: Request to switch
* transport has been completed. This is sent only in the command path. For
* example, when the driver had requested for audio transport switch and
* userspace modules as well as peers are ready for the switch, userspace module
* switches the transport and sends the subcommand with status completed to the
* driver.
*/
enum qca_wlan_audio_transport_switch_status {
QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED = 0,
QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED = 1,
};
/**
* enum qca_wlan_audio_transport_switch_reason - Represents the reason of audio
* transport switch request.
*
* @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_REASON_TERMINATING: Requester transport is
* terminating. After this indication, requester module may not be available to
* process further request on its transport. For example, to handle a high
* priority concurrent interface, WLAN transport needs to terminate and hence
* indicates switch to a non-WLAN transport with reason terminating. User space
* modules switch to non-WLAN immediately without waiting for further
* confirmation.
*/
enum qca_wlan_audio_transport_switch_reason {
QCA_WLAN_AUDIO_TRANSPORT_SWITCH_REASON_TERMINATING = 0,
};
/**
* enum qca_wlan_vendor_attr_audio_transport_switch - Attributes used by
* %QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH vendor command.
*
* @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE: u8 attribute. Indicates
* the transport switch type from one of the values in enum
* qca_wlan_audio_transport_switch_type. This is mandatory attribute in both
* command and event path. This attribute is included in both requests and
* responses.
*
* @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS: u8 attribute. Indicates
* the transport switch status from one of the values in enum
* qca_wlan_audio_transport_switch_status. This is optional attribute and used
* in both command and event path. This attribute must not be included in
* requests.
*
* @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_REASON: u8 attribute. Indicates
* the transport switch reason from one of the values in enum
* qca_wlan_audio_transport_switch_reason. This is optional attribute and used
* in both command and event path.
*/
enum qca_wlan_vendor_attr_audio_transport_switch {
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE = 1,
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS = 2,
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_REASON = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX =
QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_AFTER_LAST - 1,
};
/**
* enum qca_wlan_connect_ext_features - Feature flags for
* %QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES
*
* @QCA_CONNECT_EXT_FEATURE_RSNO: Flag attribute. This indicates supplicant
* support for RSN overriding. The driver shall enable RSN overriding in the
* (re)association attempts only if this flag is indicated. This functionality
* is available only when the driver indicates support for
* @QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA.
*
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits.
*/
enum qca_wlan_connect_ext_features {
QCA_CONNECT_EXT_FEATURE_RSNO = 0,
NUM_QCA_CONNECT_EXT_FEATURES /* keep last */
};
/* enum qca_wlan_vendor_attr_connect_ext: Attributes used by vendor command
* %QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT.
*
* @QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES: Feature flags contained in a byte
* array. The feature flags are identified by their bit index (see &enum
* qca_wlan_connect_ext_features) with the first byte being the least
* significant one and the last one being the most significant one.
*/
enum qca_wlan_vendor_attr_connect_ext {
QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES = 1,
QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_MAX =
QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_AFTER_LAST - 1,
};
/**
* enum qca_wlan_vendor_p2p_mode - Defines the values used with
* %QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG.
*
* @QCA_P2P_MODE_WFD_R1: Wi-Fi Direct R1 only.
* @QCA_P2P_MODE_WFD_R2: Wi-Fi Direct R2 only.
* @QCA_P2P_MODE_WFD_PCC: P2P Connection Compatibility Mode which supports both
* Wi-Fi Direct R1 and R2.
*/
enum qca_wlan_vendor_p2p_mode {
QCA_P2P_MODE_WFD_R1 = 0,
QCA_P2P_MODE_WFD_R2 = 1,
QCA_P2P_MODE_WFD_PCC = 2,
};
/* enum qca_wlan_vendor_attr_set_p2p_mode: Attributes used by vendor command
* %QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE.
*
* @QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG: u8 attribute. Sets the P2P device
* mode. The values used are defined in enum qca_wlan_vendor_p2p_mode.
* This configuration is valid until the interface is brought up next time after
* this configuration and the driver shall use this configuration only when the
* interface is brought up in NL80211_IFTYPE_P2P_GO mode.
* When this parameter has not been set, the interface is brought up with
* Wi-Fi Direct R1 only configuration by default.
*/
enum qca_wlan_vendor_attr_set_p2p_mode {
QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG = 1,
QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_MAX =
QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_AFTER_LAST - 1,
};
#endif /* QCA_VENDOR_H */

View file

@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
#define VERSION_STR "2.11" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#define VERSION_STR "2.12-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */

View file

@ -1890,6 +1890,14 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
data->has_group = 1;
data->key_mgmt = WPA_KEY_MGMT_OSEN;
data->proto = WPA_PROTO_OSEN;
} else if (rsn_ie_len >= 2 + 4 + 2 && rsn_ie[1] >= 4 + 2 &&
rsn_ie[1] == rsn_ie_len - 2 &&
(WPA_GET_BE32(&rsn_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE ||
WPA_GET_BE32(&rsn_ie[2]) ==
RSNE_OVERRIDE_2_IE_VENDOR_TYPE) &&
WPA_GET_LE16(&rsn_ie[2 + 4]) == RSN_VERSION) {
pos = rsn_ie + 2 + 4 + 2;
left = rsn_ie_len - 2 - 4 - 2;
} else {
const struct rsn_ie_hdr *hdr;
@ -3440,7 +3448,7 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
const u8 *p;
size_t left;
u8 link_id;
char title[50];
char title[100];
int ret;
if (len == 0)
@ -3621,6 +3629,57 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
return 0;
}
if (left >= 1 && selector == WFA_KEY_DATA_RSN_OVERRIDE_LINK) {
link_id = p[0];
if (link_id >= MAX_NUM_MLD_LINKS)
return 2;
ie->rsn_override_link[link_id] = p;
ie->rsn_override_link_len[link_id] = left;
ret = os_snprintf(title, sizeof(title),
"RSN: Link ID %u - RSN Override Link KDE in EAPOL-Key",
link_id);
if (!os_snprintf_error(sizeof(title), ret))
wpa_hexdump(MSG_DEBUG, title, pos, dlen);
return 0;
}
if (selector == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
ie->rsne_override = pos;
ie->rsne_override_len = dlen;
wpa_hexdump(MSG_DEBUG,
"RSN: RSNE Override element in EAPOL-Key",
ie->rsne_override, ie->rsne_override_len);
return 0;
}
if (selector == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
ie->rsne_override_2 = pos;
ie->rsne_override_2_len = dlen;
wpa_hexdump(MSG_DEBUG,
"RSN: RSNE Override 2 element in EAPOL-Key",
ie->rsne_override_2, ie->rsne_override_2_len);
return 0;
}
if (selector == RSNXE_OVERRIDE_IE_VENDOR_TYPE) {
ie->rsnxe_override = pos;
ie->rsnxe_override_len = dlen;
wpa_hexdump(MSG_DEBUG,
"RSN: RSNXE Override element in EAPOL-Key",
ie->rsnxe_override, ie->rsnxe_override_len);
return 0;
}
if (selector == RSN_SELECTION_IE_VENDOR_TYPE) {
ie->rsn_selection = p;
ie->rsn_selection_len = left;
wpa_hexdump(MSG_DEBUG,
"RSN: RSN Selection element in EAPOL-Key",
ie->rsn_selection, ie->rsn_selection_len);
return 0;
}
return 2;
}
@ -4260,3 +4319,24 @@ int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len)
}
#endif /* CONFIG_PASN */
void rsn_set_snonce_cookie(u8 *snonce)
{
u8 *pos;
pos = snonce + WPA_NONCE_LEN - 6;
WPA_PUT_BE24(pos, OUI_WFA);
pos += 3;
WPA_PUT_BE24(pos, 0x000029);
}
bool rsn_is_snonce_cookie(const u8 *snonce)
{
const u8 *pos;
pos = snonce + WPA_NONCE_LEN - 6;
return WPA_GET_BE24(pos) == OUI_WFA &&
WPA_GET_BE24(pos + 3) == 0x000029;
}

View file

@ -144,6 +144,7 @@ WPA_CIPHER_BIP_CMAC_256)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
#define WFA_KEY_DATA_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x21)
#define WFA_KEY_DATA_RSN_OVERRIDE_LINK RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x2d)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@ -643,6 +644,14 @@ struct wpa_pasn_params_data {
#define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
/* WPA3 specification - RSN Selection element */
enum rsn_selection_variant {
RSN_SELECTION_RSNE = 0,
RSN_SELECTION_RSNE_OVERRIDE = 1,
RSN_SELECTION_RSNE_OVERRIDE_2 = 2,
};
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int key_mgmt, bool reassoc_resp);
void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse);
@ -704,6 +713,14 @@ struct wpa_eapol_ie_parse {
u16 aid;
const u8 *wmm;
size_t wmm_len;
const u8 *rsn_selection;
size_t rsn_selection_len;
const u8 *rsne_override;
size_t rsne_override_len;
const u8 *rsne_override_2;
size_t rsne_override_2_len;
const u8 *rsnxe_override;
size_t rsnxe_override_len;
u16 valid_mlo_gtks; /* bitmap of valid link GTK KDEs */
const u8 *mlo_gtk[MAX_NUM_MLD_LINKS];
size_t mlo_gtk_len[MAX_NUM_MLD_LINKS];
@ -716,6 +733,8 @@ struct wpa_eapol_ie_parse {
u16 valid_mlo_links; /* bitmap of valid MLO link KDEs */
const u8 *mlo_link[MAX_NUM_MLD_LINKS];
size_t mlo_link_len[MAX_NUM_MLD_LINKS];
const u8 *rsn_override_link[MAX_NUM_MLD_LINKS];
size_t rsn_override_link_len[MAX_NUM_MLD_LINKS];
};
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
@ -787,4 +806,7 @@ int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len);
void rsn_set_snonce_cookie(u8 *snonce);
bool rsn_is_snonce_cookie(const u8 *snonce);
#endif /* WPA_COMMON_H */

View file

@ -13,6 +13,8 @@
extern "C" {
#endif
#define WPA_CTRL_IFACE_LINK_NAME "link"
/* wpa_supplicant control interface - fixed message prefixes */
/** Interactive request for identity/password/pin */
@ -204,6 +206,7 @@ extern "C" {
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
#define DPP_EVENT_CONFOBJ_IDPASS "DPP-CONFOBJ-IDPASS "
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
@ -225,6 +228,7 @@ extern "C" {
#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
#define DPP_EVENT_ENROLLEE_CAPABILITY "DPP-ENROLLEE-CAPABILITY "
#define DPP_EVENT_CSR "DPP-CSR "
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED "

View file

@ -27,6 +27,10 @@
#endif /* CONFIG_MACSEC */
#include "utils/list.h"
struct nan_subscribe_params;
struct nan_publish_params;
enum nan_service_protocol_type;
#define HOSTAPD_CHAN_DISABLED 0x00000001
#define HOSTAPD_CHAN_NO_IR 0x00000002
#define HOSTAPD_CHAN_RADAR 0x00000008
@ -317,6 +321,27 @@ struct hostapd_hw_modes {
};
/**
* struct hostapd_multi_hw_info: Supported multiple underlying hardware info
*/
struct hostapd_multi_hw_info {
/**
* hw_idx - Hardware index
*/
u8 hw_idx;
/**
* start_freq - Frequency range start in MHz
*/
int start_freq;
/**
* end_freq - Frequency range end in MHz
*/
int end_freq;
};
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
@ -1363,6 +1388,12 @@ struct wpa_driver_associate_params {
* mld_params - MLD association parameters
*/
struct wpa_driver_mld_params mld_params;
/**
* rsn_overriding - wpa_supplicant RSN overriding support
*/
bool rsn_overriding;
};
enum hide_ssid {
@ -2330,6 +2361,10 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP 0x0000000000100000ULL
/** Driver supports TWT responder in HT and VHT modes */
#define WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER 0x0000000000200000ULL
/** Driver supports RSN override elements */
#define WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA 0x0000000000400000ULL
/** Driver supports NAN offload */
#define WPA_DRIVER_FLAGS2_NAN_OFFLOAD 0x0000000000800000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@ -5194,15 +5229,19 @@ struct wpa_driver_ops {
/**
* is_drv_shared - Check whether the driver interface is shared
* @priv: Private driver interface data from init()
* @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
* @link_id: Link ID to match
* Returns: true if it is being used or else false.
*
* Checks whether the driver interface is being used by other partner
* BSS(s) or not. This is used to decide whether the driver interface
* needs to be deinitilized when one interface is getting deinitialized.
*
* Returns: true if it is being used or else false.
* NOTE: @link_id will be used only when there is only one BSS
* present and if that single link is active. In that case, the
* link ID is matched with the active link_id to decide whether the
* driver interface is being used by other partner BSS(s).
*/
bool (*is_drv_shared)(void *priv, void *bss_ctx);
bool (*is_drv_shared)(void *priv, int link_id);
/**
* link_sta_remove - Remove a link STA from an MLD STA
@ -5213,11 +5252,94 @@ struct wpa_driver_ops {
*/
int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr);
/**
* nan_flush - Flush all NAN offload services
* @priv: Private driver interface data
* Returns: 0 on success, negative value on failure
*/
int (*nan_flush)(void *priv);
/**
* nan_publish - NAN offload for Publish()
* @priv: Private driver interface data
* @src: Source P2P device addr
* @publish_id: Publish instance to add
* @service_name: Service name
* @service_id: Service ID (6 octet value derived from service name)
* @srv_proto_type: Service protocol type
* @ssi: Service specific information or %NULL
* @elems: Information elements for Element Container attribute or %NULL
* @params: Configuration parameters
* Returns: 0 on success, negative value on failure
*/
int (*nan_publish)(void *priv, const u8 *src, int publish_id,
const char *service_name, const u8 *service_id,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
struct nan_publish_params *params);
/**
* nan_cancel_publish - NAN offload for CancelPublish()
* @priv: Private driver interface data
* @publish_id: Publish instance to cancel
* Returns: 0 on success, negative value on failure
*/
int (*nan_cancel_publish)(void *priv, int publish_id);
/**
* nan_update_publish - NAN offload for UpdatePublish()
* @priv: Private driver interface data
* @ssi: Service specific information or %NULL
* Returns: 0 on success, negative value on failure
*/
int (*nan_update_publish)(void *priv, int publish_id,
const struct wpabuf *ssi);
/**
* nan_subscribe - NAN offload for Subscribe()
* @priv: Private driver interface data
* @src: Source P2P device addr
* @subscribe_id: Subscribe instance to add
* @service_name: Service name
* @service_id: Service ID (6 octet value derived from service name)
* @srv_proto_type: Service protocol type
* @ssi: Service specific information or %NULL
* @elems: Information elements for Element Container attribute or %NULL
* @params: Configuration parameters
* Returns: 0 on success, negative value on failure
*/
int (*nan_subscribe)(void *priv, const u8 *src, int subscribe_id,
const char *service_name, const u8 *service_id,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
const struct wpabuf *elems,
struct nan_subscribe_params *params);
/**
* nan_cancel_subscribe - NAN offload for CancelSubscribe()
* @priv: Private driver interface data
* @subscribe_id: Subscribe instance to cancel
* Returns: 0 on success, negative value on failure
*/
int (*nan_cancel_subscribe)(void *priv, int subscribe_id);
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
bool multicast);
#endif /* CONFIG_TESTING_OPTIONS */
/**
* get_multi_hw_info - Get multiple underlying hardware information
* (hardware IDx and supported frequency range)
* @priv: Private driver interface data
* @num_multi_hws: Variable for returning the number of returned
* hardware info data
* Returns: Pointer to allocated multiple hardware data on success
* or %NULL on failure. Caller is responsible for freeing this.
*/
struct hostapd_multi_hw_info *
(*get_multi_hw_info)(void *priv, unsigned int *num_multi_hws);
};
/**
@ -5845,6 +5967,11 @@ enum wpa_event_type {
* EVENT_LINK_RECONFIG - Notification that AP links removed
*/
EVENT_LINK_RECONFIG,
/**
* EVENT_MLD_INTERFACE_FREED - Notification of AP MLD interface removal
*/
EVENT_MLD_INTERFACE_FREED,
};

View file

@ -100,6 +100,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(LINK_CH_SWITCH_STARTED);
E2S(TID_LINK_MAP);
E2S(LINK_RECONFIG);
E2S(MLD_INTERFACE_FREED);
}
return "UNKNOWN";

View file

@ -19,6 +19,7 @@
#include <netlink/route/link.h>
#include <netlink/route/link/macsec.h>
#include <linux/if_macsec.h>
#include <linux/version.h>
#include <inttypes.h>
#include "utils/common.h"
@ -32,7 +33,8 @@
#define UNUSED_SCI 0xffffffffffffffff
#if LIBNL_VER_NUM >= LIBNL_VER(3, 6)
#if (LIBNL_VER_NUM >= LIBNL_VER(3, 6) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
#define LIBNL_HAS_OFFLOAD
#endif

View file

@ -3083,7 +3083,7 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
struct wpa_driver_nl80211_data *drv = bss->drv;
struct i802_link *link = nl80211_get_link(bss, link_id);
if (!link->beacon_set)
if (!link || !link->beacon_set)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
@ -3151,9 +3151,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
bss->ifname, bss->brname, strerror(errno));
}
if (drv->rtnl_sk)
nl_socket_free(drv->rtnl_sk);
if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
0) < 0)
@ -3173,6 +3170,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
nl80211_remove_links(bss);
}
if (drv->rtnl_sk)
nl_socket_free(drv->rtnl_sk);
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
close(drv->eapol_sock);
@ -3189,7 +3189,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
rfkill_deinit(drv->rfkill);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
@ -4207,6 +4207,22 @@ struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id)
}
u8 nl80211_get_link_id_from_link(struct i802_bss *bss, struct i802_link *link)
{
u8 link_id;
if (link == bss->flink)
return 0;
for_each_link(bss->valid_links, link_id) {
if (&bss->links[link_id] == link)
return link_id;
}
return 0;
}
static void nl80211_link_set_freq(struct i802_bss *bss, s8 link_id, int freq)
{
struct i802_link *link = nl80211_get_link(bss, link_id);
@ -5865,13 +5881,15 @@ fail:
}
static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr,
bool is_bridge)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ndmsg nhdr = {
.ndm_state = NUD_PERMANENT,
.ndm_ifindex = bss->ifindex,
.ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
.ndm_family = AF_BRIDGE,
.ndm_type = is_bridge ? NTF_SELF : 0,
};
struct nl_msg *msg;
int err;
@ -5888,11 +5906,61 @@ static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
bss->ifindex, nl_geterror(err));
MACSTR " ifindex=%d ifname %s failed: %s",
MAC2STR(addr),
is_bridge ? bss->br_ifindex : bss->ifindex,
is_bridge ? bss->brname : bss->ifname,
nl_geterror(err));
} else {
wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
MACSTR, MAC2STR(addr));
wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry "
MACSTR " from %s",
MAC2STR(addr),
is_bridge ? bss->brname : bss->ifname);
}
errout:
nlmsg_free(msg);
}
static void rtnl_neigh_add_fdb_entry(struct i802_bss *bss, const u8 *addr,
bool is_bridge)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ndmsg nhdr = {
.ndm_state = NUD_PERMANENT,
.ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
.ndm_family = AF_BRIDGE,
/* TODO: remove this check if this flag needs to be used,
* for other interfaces type.
*/
.ndm_flags = is_bridge ? NTF_SELF : 0,
};
struct nl_msg *msg;
int err;
msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
if (!msg)
return;
if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) ||
nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
goto errout;
err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry addition for "
MACSTR " ifindex=%d ifname %s failed: %s",
MAC2STR(addr),
is_bridge ? bss->br_ifindex : bss->ifindex,
is_bridge ? bss->brname : bss->ifname,
nl_geterror(err));
} else {
wpa_printf(MSG_DEBUG, "nl80211: added bridge FDB entry " MACSTR
" to %s",
MAC2STR(addr),
is_bridge ? bss->brname : bss->ifname);
}
errout:
@ -5927,7 +5995,7 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
if (drv->rtnl_sk)
rtnl_neigh_delete_fdb_entry(bss, addr);
rtnl_neigh_delete_fdb_entry(bss, addr, false);
if (ret == -ENOENT)
return 0;
@ -7066,6 +7134,60 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
}
#ifdef CONFIG_DRIVER_NL80211_QCA
static void connect_ext_feature_set(u8 *features,
enum qca_wlan_connect_ext_features idx)
{
u8 *idx_byte = &features[idx / 8];
*idx_byte |= BIT(idx % 8);
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
static int nl80211_connect_ext(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
#ifdef CONFIG_DRIVER_NL80211_QCA
struct nl_msg *msg;
struct nlattr *attr;
u8 features[(NUM_QCA_CONNECT_EXT_FEATURES + 7) / 8] = {};
if (!drv->connect_ext_vendor_cmd_avail)
return -1;
wpa_printf(MSG_DEBUG, "nl80211: Connect_ext (ifindex=%d)",
drv->ifindex);
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT))
goto fail;
attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
if (!attr)
goto fail;
if (params->rsn_overriding) {
wpa_printf(MSG_DEBUG, "- RSN overriding");
connect_ext_feature_set(features, QCA_CONNECT_EXT_FEATURE_RSNO);
}
if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES,
sizeof(features), features))
goto fail;
nla_nest_end(msg, attr);
return send_and_recv_cmd(drv, msg);
fail:
nlmsg_free(msg);
#endif /* CONFIG_DRIVER_NL80211_QCA */
return -1;
}
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
@ -7087,6 +7209,7 @@ static int wpa_driver_nl80211_try_connect(
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
nl80211_connect_ext(drv, params);
wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
if (!msg)
@ -8420,6 +8543,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
struct wpa_driver_nl80211_data *drv = bss->drv;
char name[IFNAMSIZ + 1];
union wpa_event_data event;
bool add_br = false;
int ret;
ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
@ -8441,10 +8565,9 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
bss->addr, 1, NULL, NULL, 0) <
0)
return -1;
if (bridge_ifname &&
linux_br_add_if(drv->global->ioctl_sock,
bridge_ifname, name) < 0)
return -1;
if (bridge_ifname)
add_br = true;
os_memset(&event, 0, sizeof(event));
event.wds_sta_interface.sta_addr = addr;
@ -8458,6 +8581,12 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
"interface %s up", name);
}
if (add_br &&
linux_br_add_if(drv->global->ioctl_sock,
bridge_ifname, name) < 0)
return -1;
return i802_set_sta_vlan(priv, addr, name, 0,
NL80211_DRV_LINK_ID_NA);
} else {
@ -9442,13 +9571,14 @@ fail:
}
static int nl80211_remove_link(struct i802_bss *bss, int link_id)
int nl80211_remove_link(struct i802_bss *bss, int link_id)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct i802_link *link;
struct nl_msg *msg;
size_t i;
int ret;
u8 link_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)",
bss->ifindex, link_id);
@ -9463,6 +9593,7 @@ static int nl80211_remove_link(struct i802_bss *bss, int link_id)
wpa_driver_nl80211_del_beacon(bss, link_id);
os_memcpy(link_addr, link->addr, ETH_ALEN);
/* First remove the link locally */
bss->valid_links &= ~BIT(link_id);
os_memset(link->addr, 0, ETH_ALEN);
@ -9500,6 +9631,9 @@ static int nl80211_remove_link(struct i802_bss *bss, int link_id)
"nl80211: remove link (%d) failed. ret=%d (%s)",
link_id, ret, strerror(-ret));
if (drv->rtnl_sk)
rtnl_neigh_delete_fdb_entry(bss, link_addr, true);
return ret;
}
@ -9899,6 +10033,9 @@ static int nl80211_set_param(void *priv, const char *param)
WPA_DRIVER_FLAGS2_SEC_LTF_AP;
}
if (os_strstr(param, "rsn_override_in_driver=1"))
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA;
return 0;
}
@ -10249,6 +10386,8 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
int err;
union wpa_event_data data;
struct survey_results *survey_results;
void *ctx = (bss->scan_link && bss->scan_link->ctx) ?
bss->scan_link->ctx : bss->ctx;
os_memset(&data, 0, sizeof(data));
survey_results = &data.survey_results;
@ -10271,7 +10410,7 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
if (err)
wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
else
wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
wpa_supplicant_event(ctx, EVENT_SURVEY, &data);
clean_survey_results(survey_results);
return err;
@ -10744,6 +10883,7 @@ static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type,
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret;
if (type != WPA_IF_AP_BSS ||
!nl80211_link_valid(bss->valid_links, link_id))
@ -10763,18 +10903,25 @@ static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type,
if (!bss->valid_links) {
wpa_printf(MSG_DEBUG,
"nl80211: No more links remaining, so remove interface");
return wpa_driver_nl80211_if_remove(bss, type, ifname);
ret = wpa_driver_nl80211_if_remove(bss, type, ifname);
if (ret)
return ret;
/* Notify that the MLD interface is removed */
wpa_supplicant_event(bss->ctx, EVENT_MLD_INTERFACE_FREED, NULL);
}
return 0;
}
static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
static bool nl80211_is_drv_shared(void *priv, int link_id)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
unsigned int num_bss = 0;
unsigned int num_bss = 0, num_links = 0;
bool self = false;
u8 i;
/* If any other BSS exist, someone else is using this since at this
* time, we would have removed all BSSs created by this driver and only
@ -10789,13 +10936,23 @@ static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
/* This is the only BSS present */
bss = priv;
/* If only one/no link is there no one is sharing */
if (bss->valid_links <= 1)
for_each_link(bss->valid_links, i) {
num_links++;
if (i == link_id)
self = true;
}
/* More than one links means some one is still sharing */
if (num_links > 1)
return true;
/* Even if only one link is there, it should match the given
* link ID to assert that no one else is sharing. */
if (num_links == 1 && self)
return false;
/* More than one link means someone is still using. To check if
* only 1 bit is set, power of 2 condition can be checked. */
if (!(bss->valid_links & (bss->valid_links - 1)))
/* No links are active means no one is sharing */
if (num_links == 0)
return false;
return true;
@ -13918,6 +14075,10 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr,
wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s",
bss->valid_links, bss->ifname);
if (drv->rtnl_sk)
rtnl_neigh_add_fdb_entry(bss, addr, true);
return 0;
}
@ -13997,6 +14158,15 @@ static int testing_nl80211_radio_disable(void *priv, int disabled)
#endif /* CONFIG_TESTING_OPTIONS */
static struct hostapd_multi_hw_info *
wpa_driver_get_multi_hw_info(void *priv, unsigned int *num_multi_hws)
{
struct i802_bss *bss = priv;
return nl80211_get_multi_hw_info(bss, num_multi_hws);
}
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@ -14155,4 +14325,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.register_frame = testing_nl80211_register_frame,
.radio_disable = testing_nl80211_radio_disable,
#endif /* CONFIG_TESTING_OPTIONS */
.get_multi_hw_info = wpa_driver_get_multi_hw_info,
};

View file

@ -67,7 +67,7 @@ struct i802_bss {
u16 valid_links;
struct i802_link links[MAX_NUM_MLD_LINKS];
struct i802_link *flink;
struct i802_link *flink, *scan_link;
int ifindex;
int br_ifindex;
@ -200,6 +200,7 @@ struct wpa_driver_nl80211_data {
unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
unsigned int puncturing:1;
unsigned int qca_ap_allowed_freqs:1;
unsigned int connect_ext_vendor_cmd_avail:1;
u32 ignore_next_local_disconnect;
u32 ignore_next_local_deauth;
@ -352,6 +353,8 @@ const char * nl80211_iftype_str(enum nl80211_iftype mode);
void nl80211_restore_ap_mode(struct i802_bss *bss);
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
u8 nl80211_get_link_id_from_link(struct i802_bss *bss, struct i802_link *link);
int nl80211_remove_link(struct i802_bss *bss, int link_id);
static inline bool nl80211_link_valid(u16 links, s8 link_id)
{
@ -409,5 +412,7 @@ int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie);
int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
struct hostapd_multi_hw_info *
nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws);
#endif /* DRIVER_NL80211_H */

View file

@ -1120,6 +1120,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT:
drv->secure_ranging_ctx_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT:
drv->connect_ext_vendor_cmd_avail = 1;
break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
#ifdef CONFIG_DRIVER_NL80211_BRCM
@ -1443,6 +1446,12 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
drv->qca_ap_allowed_freqs = 1;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER, &info))
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA, &info)) {
wpa_printf(MSG_DEBUG,
"The driver supports RSN overriding in STA mode");
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA;
}
os_free(info.flags);
}
@ -1470,6 +1479,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
WPA_DRIVER_CAPA_KEY_MGMT_OWE |
WPA_DRIVER_CAPA_KEY_MGMT_DPP;
@ -1485,6 +1495,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY |
WPA_DRIVER_CAPA_KEY_MGMT_SAE;
else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
drv->capa.key_mgmt |=
@ -2728,3 +2739,133 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
return NULL;
}
static int phy_multi_hw_info_parse(struct hostapd_multi_hw_info *hw_info,
struct nlattr *radio_attr)
{
struct nlattr *tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_MAX + 1];
int start_freq, end_freq;
switch (nla_type(radio_attr)) {
case NL80211_WIPHY_RADIO_ATTR_INDEX:
hw_info->hw_idx = nla_get_u32(radio_attr);
return NL_OK;
case NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE:
nla_parse_nested(tb_freq, NL80211_WIPHY_RADIO_FREQ_ATTR_MAX,
radio_attr, NULL);
if (!tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_START] ||
!tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_END])
return NL_STOP;
start_freq = nla_get_u32(
tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_START]);
end_freq = nla_get_u32(
tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_END]);
/* Convert to MHz and store */
hw_info->start_freq = start_freq / 1000;
hw_info->end_freq = end_freq / 1000;
return NL_OK;
default:
return NL_OK;
}
}
struct phy_multi_hw_info_arg {
bool failed;
unsigned int *num_multi_hws;
struct hostapd_multi_hw_info *multi_hws;
};
static int phy_multi_hw_info_handler(struct nl_msg *msg, void *arg)
{
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct phy_multi_hw_info_arg *multi_hw_info = arg;
struct hostapd_multi_hw_info *multi_hws, hw_info;
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
struct nlattr *nl_hw, *radio_attr;
int rem_hw, rem_radio_prop, res;
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb_msg[NL80211_ATTR_WIPHY_RADIOS])
return NL_SKIP;
*multi_hw_info->num_multi_hws = 0;
nla_for_each_nested(nl_hw, tb_msg[NL80211_ATTR_WIPHY_RADIOS], rem_hw) {
os_memset(&hw_info, 0, sizeof(hw_info));
nla_for_each_nested(radio_attr, nl_hw, rem_radio_prop) {
res = phy_multi_hw_info_parse(&hw_info, radio_attr);
if (res != NL_OK)
goto out;
}
if (hw_info.start_freq == 0 || hw_info.end_freq == 0)
goto out;
multi_hws = os_realloc_array(multi_hw_info->multi_hws,
*multi_hw_info->num_multi_hws + 1,
sizeof(*multi_hws));
if (!multi_hws)
goto out;
multi_hw_info->multi_hws = multi_hws;
os_memcpy(&multi_hws[*(multi_hw_info->num_multi_hws)],
&hw_info, sizeof(struct hostapd_multi_hw_info));
*(multi_hw_info->num_multi_hws) += 1;
}
return NL_OK;
out:
multi_hw_info->failed = true;
return NL_STOP;
}
struct hostapd_multi_hw_info *
nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws)
{
u32 feat;
struct wpa_driver_nl80211_data *drv = bss->drv;
int nl_flags = 0;
struct nl_msg *msg;
struct phy_multi_hw_info_arg result = {
.failed = false,
.num_multi_hws = num_multi_hws,
.multi_hws = NULL,
};
*num_multi_hws = 0;
if (!drv->has_capability || !(drv->capa.flags2 & WPA_DRIVER_FLAGS2_MLO))
return NULL;
feat = get_nl80211_protocol_features(drv);
if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
nl_flags = NLM_F_DUMP;
if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
nlmsg_free(msg);
return NULL;
}
if (send_and_recv_resp(drv, msg, phy_multi_hw_info_handler,
&result) == 0) {
if (result.failed) {
os_free(result.multi_hws);
*num_multi_hws = 0;
return NULL;
}
return result.multi_hws;
}
return NULL;
}

View file

@ -186,6 +186,7 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_REMOVE_LINK_STA)
C2S(NL80211_CMD_SET_HW_TIMESTAMP)
C2S(NL80211_CMD_LINKS_REMOVED)
C2S(NL80211_CMD_SET_TID_TO_LINK_MAPPING)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@ -1204,9 +1205,6 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
int chan_offset = 0;
int ifidx;
wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event",
finished ? "" : " started");
if (!freq)
return;
@ -1218,6 +1216,9 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
return;
}
wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event for %s",
finished ? "" : " started", bss->ifname);
if (type) {
enum nl80211_channel_type ch_type = nla_get_u32(type);
@ -1260,10 +1261,13 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
if (cf2)
data.ch_switch.cf2 = nla_get_u32(cf2);
if (link)
if (link) {
data.ch_switch.link_id = nla_get_u8(link);
else
wpa_printf(MSG_DEBUG, "nl80211: Link ID: %d",
data.ch_switch.link_id);
} else {
data.ch_switch.link_id = NL80211_DRV_LINK_ID_NA;
}
if (finished) {
if (data.ch_switch.link_id != NL80211_DRV_LINK_ID_NA) {
@ -1300,6 +1304,14 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
return;
}
if (link && is_ap_interface(drv->nlmode) &&
!nl80211_link_valid(bss->valid_links, data.ch_switch.link_id)) {
wpa_printf(MSG_WARNING,
"nl80211: Unknown link ID (%d) for channel switch (%s), ignoring",
data.ch_switch.link_id, bss->ifname);
return;
}
drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, finished ?
@ -1965,9 +1977,10 @@ static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv,
}
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
static void send_scan_event(struct i802_bss *bss, int aborted,
struct nlattr *tb[], int external_scan)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
union wpa_event_data event;
struct nlattr *nl;
int rem;
@ -1975,6 +1988,8 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
#define MAX_REPORT_FREQS 110
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
struct i802_link *mld_link;
void *ctx = bss->ctx;
if (!external_scan && drv->scan_for_auth) {
drv->scan_for_auth = 0;
@ -2038,13 +2053,30 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
ETH_ALEN);
}
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
/* Need to pass to the correct link ctx during AP MLD operation */
if (is_ap_interface(drv->nlmode)) {
mld_link = bss->scan_link;
if (!mld_link) {
wpa_printf(MSG_DEBUG,
"nl80211: Scan event on unknown link");
} else if (mld_link->ctx) {
u8 link_id = nl80211_get_link_id_from_link(bss,
mld_link);
wpa_printf(MSG_DEBUG,
"nl80211: Scan event for link_id %d",
link_id);
ctx = mld_link->ctx;
}
}
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, &event);
}
static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
struct nlattr *tb[])
static void nl80211_cqm_event(struct i802_bss *bss, struct nlattr *tb[])
{
struct wpa_driver_nl80211_data *drv = bss->drv;
static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
@ -2079,7 +2111,7 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Packet loss event for " MACSTR
" (num_packets %u)",
MAC2STR(ed.low_ack.addr), ed.low_ack.num_packets);
wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
wpa_supplicant_event(bss->ctx, EVENT_STATION_LOW_ACK, &ed);
return;
}
@ -2411,10 +2443,33 @@ static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
}
static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
static void nl80211_stop_ap(struct i802_bss *bss, struct nlattr **tb)
{
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
struct i802_link *mld_link = NULL;
void *ctx = bss->ctx;
int link_id = -1;
if (tb[NL80211_ATTR_MLO_LINK_ID]) {
link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
if (!nl80211_link_valid(bss->valid_links, link_id)) {
wpa_printf(MSG_DEBUG,
"nl80211: Ignoring STOP_AP event for invalid link ID %d (valid: 0x%04x)",
link_id, bss->valid_links);
return;
}
mld_link = nl80211_get_link(bss, link_id);
wpa_printf(MSG_DEBUG,
"nl80211: STOP_AP event on link %d", link_id);
ctx = mld_link->ctx;
/* The driver would have already deleted the link and this call
* will return an error. Ignore that since nl80211_remove_link()
* is called here only to update the bss->links[] state. */
nl80211_remove_link(bss, link_id);
}
wpa_supplicant_event(ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
}
@ -3055,7 +3110,7 @@ static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv,
drv->scan_state = SCAN_ABORTED;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
drv->first_bss->ctx);
drv->vendor_scan_cookie = 0;
drv->last_scan_cmd = 0;
}
@ -3894,7 +3949,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Scan trigger");
drv->scan_state = SCAN_STARTED;
if (drv->scan_for_auth) {
/*
@ -3906,40 +3961,40 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
break;
}
wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
wpa_supplicant_event(bss->ctx, EVENT_SCAN_STARTED, NULL);
break;
case NL80211_CMD_START_SCHED_SCAN:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Sched scan started");
drv->scan_state = SCHED_SCAN_STARTED;
break;
case NL80211_CMD_SCHED_SCAN_STOPPED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
drv->scan_state = SCHED_SCAN_STOPPED;
wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
wpa_supplicant_event(bss->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
wpa_dbg(bss->ctx, MSG_DEBUG,
"nl80211: New scan results available");
if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv, bss->ctx);
drv->last_scan_cmd = 0;
} else {
external_scan_event = 1;
}
send_scan_event(drv, 0, tb, external_scan_event);
send_scan_event(bss, 0, tb, external_scan_event);
break;
case NL80211_CMD_SCHED_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
wpa_dbg(bss->ctx, MSG_DEBUG,
"nl80211: New sched scan results available");
drv->scan_state = SCHED_SCAN_RESULTS;
send_scan_event(drv, 0, tb, 0);
send_scan_event(bss, 0, tb, 0);
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Scan aborted");
if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_ABORTED;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
@ -3948,12 +4003,12 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
* order not to make wpa_supplicant stop its scanning.
*/
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv, bss->ctx);
drv->last_scan_cmd = 0;
} else {
external_scan_event = 1;
}
send_scan_event(drv, 1, tb, external_scan_event);
send_scan_event(bss, 1, tb, external_scan_event);
break;
case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE:
@ -4031,7 +4086,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
mlme_event_remain_on_channel(drv, 1, tb);
break;
case NL80211_CMD_NOTIFY_CQM:
nl80211_cqm_event(drv, tb);
nl80211_cqm_event(bss, tb);
break;
case NL80211_CMD_REG_CHANGE:
case NL80211_CMD_WIPHY_REG_CHANGE:
@ -4068,7 +4123,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
nl80211_radar_event(drv, tb);
break;
case NL80211_CMD_STOP_AP:
nl80211_stop_ap(drv, tb);
nl80211_stop_ap(bss, tb);
break;
case NL80211_CMD_VENDOR:
nl80211_vendor_event(drv, tb);
@ -4202,7 +4257,16 @@ int process_global_event(struct nl_msg *msg, void *arg)
wdev_id == bss->wdev_id)) {
processed = true;
do_process_drv_event(bss, gnlh->cmd, tb);
if (!wiphy_idx_set)
/* There are two types of events that may need
* to be delivered to multiple interfaces:
* 1. Events for a wiphy, as it can have
* multiple interfaces.
* 2. "Global" events, like
* NL80211_CMD_REG_CHANGE.
*
* Terminate early only if the event is directed
* to a specific interface or wdev. */
if (ifidx != -1 || wdev_id_set)
return NL_SKIP;
/* The driver instance could have been removed,
* e.g., due to NL80211_CMD_RADAR_DETECT event,

View file

@ -153,6 +153,7 @@ fail:
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
struct i802_bss *bss;
wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
#ifdef CONFIG_DRIVER_NL80211_QCA
@ -160,14 +161,27 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0)
return;
#endif /* CONFIG_DRIVER_NL80211_QCA */
if (!drv->vendor_scan_cookie &&
nl80211_abort_scan(drv->first_bss) == 0)
for (bss = drv->first_bss; bss; bss = bss->next) {
if (bss->scan_link)
break;
}
if (!bss) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to find scan BSS");
return;
}
if (!drv->vendor_scan_cookie &&
nl80211_abort_scan(bss) == 0) {
bss->scan_link = NULL;
return;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED)
nl80211_restore_ap_mode(drv->first_bss);
nl80211_restore_ap_mode(bss);
wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@ -347,7 +361,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
int ret = -1, timeout;
struct nl_msg *msg = NULL;
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: scan request");
drv->scan_for_auth = 0;
if (TEST_FAIL())
@ -402,6 +416,40 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
"(%s)", ret, strerror(-ret));
if (drv->hostapd && is_ap_interface(drv->nlmode)) {
#ifdef CONFIG_IEEE80211BE
/* For multi link BSS, retry scan if any other links
* are busy scanning. */
if (ret == -EBUSY &&
nl80211_link_valid(bss->valid_links,
params->link_id)) {
struct i802_bss *link_bss;
u8 link_id;
wpa_printf(MSG_DEBUG,
"nl80211: Scan trigger on multi link BSS failed (requested link=%d on interface %s)",
params->link_id, bss->ifname);
for (link_bss = drv->first_bss; link_bss;
link_bss = link_bss->next) {
if (link_bss->scan_link)
break;
}
if (!link_bss) {
wpa_printf(MSG_DEBUG,
"nl80211: BSS information already running scan not available");
goto fail;
}
link_id = nl80211_get_link_id_from_link(
link_bss, link_bss->scan_link);
wpa_printf(MSG_DEBUG,
"nl80211: Scan already running on interface %s link %d",
link_bss->ifname, link_id);
goto fail;
}
#endif /* CONFIG_IEEE80211BE */
/*
* mac80211 does not allow scan requests in AP mode, so
* try to do this in station mode.
@ -435,11 +483,20 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
}
wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
"seconds", ret, timeout);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv, bss->ctx);
drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;
bss->scan_link = bss->flink;
if (is_ap_interface(drv->nlmode) &&
nl80211_link_valid(bss->valid_links, params->link_id)) {
wpa_dbg(bss->ctx, MSG_DEBUG,
"nl80211: Scan requested for link %d",
params->link_id);
bss->scan_link = nl80211_get_link(bss, params->link_id);
}
fail:
nlmsg_free(msg);
return ret;
@ -1294,9 +1351,9 @@ int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
wpa_printf(MSG_DEBUG,
"nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
ret, (long long unsigned int) cookie);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv, bss->ctx);
drv->last_scan_cmd = NL80211_CMD_VENDOR;
fail:

File diff suppressed because it is too large Load diff

View file

@ -18,11 +18,6 @@
#include "fst/fst_ctrl_defs.h"
#endif /* CONFIG_FST_TEST */
#define US_80211_TU 1024
#define US_TO_TU(m) ((m) * / US_80211_TU)
#define TU_TO_US(m) ((m) * US_80211_TU)
#define FST_LLT_SWITCH_IMMEDIATELY 0
#define fst_printf_session(s, level, format, ...) \
@ -182,7 +177,8 @@ static void fst_session_timeout_handler(void *eloop_data, void *user_ctx)
static void fst_session_stt_arm(struct fst_session *s)
{
/* Action frames sometimes get delayed. Use relaxed timeout (2*) */
eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
eloop_register_timeout(0,
2 * TU_TO_USEC(FST_DEFAULT_SESSION_TIMEOUT_TU),
fst_session_timeout_handler, NULL, s);
s->stt_armed = true;
}

View file

@ -954,6 +954,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
dev->info.wps_vendor_ext[i] = NULL;
}
os_free(dev->bootstrap_params);
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
@ -1599,7 +1600,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id,
bool p2p2, u16 bootstrap, const char *password)
{
struct p2p_device *dev;
@ -1683,6 +1685,10 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
dev->wps_method = wps_method;
dev->oob_pw_id = oob_pw_id;
dev->p2p2 = p2p2;
dev->req_bootstrap_method = bootstrap;
if (password && os_strlen(password) < sizeof(dev->password))
os_strlcpy(dev->password, password, sizeof(dev->password));
dev->status = P2P_SC_SUCCESS;
if (p2p->p2p_scan_running) {
@ -1701,7 +1707,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
unsigned int pref_freq, u16 oob_pw_id)
unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap,
const char *password)
{
struct p2p_device *dev;
@ -1735,6 +1742,10 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
dev->req_bootstrap_method = bootstrap;
if (password && os_strlen(password) < sizeof(dev->password))
os_strlcpy(dev->password, password, sizeof(dev->password));
p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@ -1924,10 +1935,10 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break;
case P2P_PROV_DISC_REQ:
p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_PROV_DISC_RESP:
p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1);
p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_DEV_DISC_REQ:
p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
@ -2968,6 +2979,44 @@ bool is_p2p_6ghz_disabled(struct p2p_data *p2p)
}
static void p2p_pairing_info_deinit(struct p2p_data *p2p)
{
os_free(p2p->pairing_info);
}
static int p2p_pairing_info_init(struct p2p_data *p2p)
{
struct p2p_pairing_info *pairing_info;
if (p2p->cfg->pairing_config.dik_len > DEVICE_IDENTITY_KEY_MAX_LEN)
return -1;
pairing_info = os_zalloc(sizeof(struct p2p_pairing_info));
if (!pairing_info)
return -1;
pairing_info->enable_pairing_setup =
p2p->cfg->pairing_config.enable_pairing_setup;
pairing_info->enable_pairing_cache =
p2p->cfg->pairing_config.enable_pairing_cache;
pairing_info->supported_bootstrap =
p2p->cfg->pairing_config.bootstrap_methods;
pairing_info->dev_ik.cipher_version =
p2p->cfg->pairing_config.dik_cipher;
pairing_info->dev_ik.dik_len = p2p->cfg->pairing_config.dik_len;
os_memcpy(pairing_info->dev_ik.dik_data,
p2p->cfg->pairing_config.dik_data,
p2p->cfg->pairing_config.dik_len);
p2p_pairing_info_deinit(p2p);
p2p->pairing_info = pairing_info;
return 0;
}
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
@ -3023,6 +3072,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->go_timeout = 100;
p2p->client_timeout = 20;
p2p->num_p2p_sd_queries = 0;
/* Default comeback after one second */
if (!p2p->cfg->comeback_after)
p2p->cfg->comeback_after = 977; /* TUs */
p2p_pairing_info_init(p2p);
p2p_dbg(p2p, "initialized");
p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
@ -3066,6 +3119,7 @@ void p2p_deinit(struct p2p_data *p2p)
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
p2p_pairing_info_deinit(p2p);
os_free(p2p);
}
@ -3399,7 +3453,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
if (!ether_addr_equal(p2p->pending_pd_devaddr,
dev->info.p2p_device_addr))
continue;
if (!dev->req_config_methods)
if (!dev->req_config_methods && !dev->req_bootstrap_method)
continue;
p2p_dbg(p2p, "Send pending Provision Discovery Request to "
@ -5688,3 +5742,184 @@ void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value)
{
p2p->allow_6ghz = value;
}
static int p2p_derive_nonce_tag(struct p2p_data *p2p)
{
u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN];
u8 dira_tag[DEVICE_MAX_HASH_LEN];
u8 data[DIR_STR_LEN + DEVICE_IDENTITY_NONCE_LEN + ETH_ALEN];
struct p2p_id_key *dev_ik;
dev_ik = &p2p->pairing_info->dev_ik;
if (dev_ik->cipher_version != DIRA_CIPHER_VERSION_128) {
wpa_printf(MSG_INFO,
"P2P: Unsupported DIRA Cipher version = %d",
dev_ik->cipher_version);
return -1;
}
if (dev_ik->dik_len != DEVICE_IDENTITY_KEY_LEN) {
wpa_printf(MSG_INFO, "P2P: Invalid DIK length = %zu",
dev_ik->dik_len);
return -1;
}
os_memset(data, 0, sizeof(data));
if (os_get_random(dira_nonce, DEVICE_IDENTITY_NONCE_LEN) < 0) {
wpa_printf(MSG_ERROR, "P2P: Failed to generate DIRA nonce");
return -1;
}
/* Tag = Truncate-64(HMAC-SHA-256(DevIK,
* "DIR" || P2P Device Address || Nonce))
*/
os_memcpy(data, "DIR", DIR_STR_LEN);
os_memcpy(&data[DIR_STR_LEN], p2p->cfg->dev_addr, ETH_ALEN);
os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], dira_nonce,
DEVICE_IDENTITY_NONCE_LEN);
if (hmac_sha256(dev_ik->dik_data, dev_ik->dik_len, data, sizeof(data),
dira_tag) < 0) {
wpa_printf(MSG_ERROR, "P2P: Could not derive DIRA tag");
return -1;
}
dev_ik->dira_nonce_len = DEVICE_IDENTITY_NONCE_LEN;
os_memcpy(dev_ik->dira_nonce, dira_nonce, DEVICE_IDENTITY_NONCE_LEN);
dev_ik->dira_tag_len = DEVICE_IDENTITY_TAG_LEN;
os_memcpy(dev_ik->dira_tag, dira_tag, DEVICE_IDENTITY_TAG_LEN);
wpa_hexdump_key(MSG_DEBUG, "P2P: DIK", dev_ik->dik_data,
dev_ik->dik_len);
wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-NONCE", dev_ik->dira_nonce,
dev_ik->dira_nonce_len);
wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-TAG", dev_ik->dira_tag,
dev_ik->dira_tag_len);
return 0;
}
struct wpabuf * p2p_usd_elems(struct p2p_data *p2p)
{
struct wpabuf *buf;
u8 *len;
u8 group_capab;
buf = wpabuf_alloc(1000);
if (!buf)
return NULL;
len = p2p_buf_add_ie_hdr(buf);
/* P2P Capability attribute */
group_capab = 0;
if (p2p->num_groups) {
group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
(p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
}
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
p2p_buf_add_capability(buf, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
/* P2P Device Info attribute */
p2p_buf_add_device_info(buf, p2p, NULL);
p2p_buf_update_ie_hdr(buf, len);
len = p2p_buf_add_p2p2_ie_hdr(buf);
/* P2P Capability Extension attribute */
p2p_buf_add_pcea(buf, p2p);
/* P2P Pairing Bootstrapping Method attribute */
p2p_buf_add_pbma(buf, p2p->cfg->pairing_config.bootstrap_methods, NULL,
0, 0);
/* P2P Device Identity Resolution attribute */
if (p2p->pairing_info &&
p2p->cfg->pairing_config.pairing_capable &&
p2p->cfg->pairing_config.enable_pairing_cache &&
p2p->cfg->pairing_config.enable_pairing_verification &&
p2p_derive_nonce_tag(p2p) == 0)
p2p_buf_add_dira(buf, p2p);
p2p_buf_update_ie_hdr(buf, len);
return buf;
}
void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
p2p_parse_free(&msg);
return;
}
if (msg.p2p_device_addr)
p2p_dev_addr = msg.p2p_device_addr;
else
p2p_dev_addr = peer_addr;
dev = p2p_create_device(p2p, p2p_dev_addr);
if (!dev) {
p2p_parse_free(&msg);
p2p_dbg(p2p, "Failed to add a peer P2P Device");
return;
}
dev->p2p2 = true;
/* Reset info from old IEs */
dev->info.reg_info = 0;
os_memset(&dev->info.pairing_config, 0,
sizeof(struct p2p_pairing_config));
os_get_reltime(&dev->last_seen);
dev->listen_freq = freq;
dev->oper_freq = freq;
if (msg.capability) {
/*
* P2P Client Discoverability bit is reserved in all frames
* that use this function, so do not change its value here.
*/
dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
dev->info.dev_capab |= msg.capability[0] &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
dev->info.group_capab = msg.capability[1];
}
if (msg.pcea_info && msg.pcea_info_len >= 2)
p2p_process_pcea(p2p, &msg, dev);
if (msg.pbma_info && msg.pbma_info_len == 2)
dev->info.pairing_config.bootstrap_methods =
WPA_GET_LE16(msg.pbma_info);
if (!ether_addr_equal(peer_addr, p2p_dev_addr))
os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN);
p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR
" dev_capab=0x%x group_capab=0x%x listen_freq=%d",
MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
dev->info.group_capab, dev->listen_freq);
p2p->cfg->dev_found(p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
&dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE));
p2p_parse_free(&msg);
}

View file

@ -12,6 +12,16 @@
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
#define DEVICE_IDENTITY_KEY_MAX_LEN 64
#define DEVICE_IDENTITY_KEY_LEN 16
#define DEVICE_IDENTITY_TAG_LEN 8
#define DEVICE_IDENTITY_NONCE_LEN 8
#define DEVICE_MAX_HASH_LEN 32
#define DIR_STR_LEN 3
/* DIRA Cipher versions */
#define DIRA_CIPHER_VERSION_128 0
struct weighted_pcl;
/* P2P ASP Setup Capability */
@ -320,6 +330,50 @@ enum p2p_scan_type {
#define P2P_MAX_WPS_VENDOR_EXT 10
/**
* struct p2p_pairing_config - P2P pairing configuration
*/
struct p2p_pairing_config {
/**
* Pairing capable
*/
bool pairing_capable;
/**
* Enable P2P pairing setup
*/
bool enable_pairing_setup;
/**
* Enable pairing cache to allow verification
*/
bool enable_pairing_cache;
/**
* Enable P2P pairing verification with cached NIK/NPK
*/
bool enable_pairing_verification;
/**
* P2P bootstrapping methods supported
*/
u16 bootstrap_methods;
/**
* Bitmap of supported PASN types
*/
u8 pasn_type;
/* Cipher version type */
int dik_cipher;
/* Buffer to hold the DevIK */
u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
/* Length of DevIK in octets */
size_t dik_len;
};
/**
* struct p2p_peer_info - P2P peer information
*/
@ -411,6 +465,21 @@ struct p2p_peer_info {
* p2ps_instance - P2PS Application Service Info
*/
struct wpabuf *p2ps_instance;
/**
* pcea_cap_info - Capability info in PCEA
*/
u16 pcea_cap_info;
/**
* The regulatory info encoding for operation in 6 GHz band
*/
u8 reg_info;
/**
* p2p_pairing_config - P2P pairing configuration
*/
struct p2p_pairing_config pairing_config;
};
enum p2p_prov_disc_status {
@ -589,6 +658,33 @@ struct p2p_config {
*/
unsigned int passphrase_len;
/**
* p2p_pairing_config - P2P pairing configuration
*/
struct p2p_pairing_config pairing_config;
/**
* reg_info - Regulatory info encoding for operation in 6 GHz band
*/
u8 reg_info;
/**
* dfs_owner - Enable P2P GO to act as DFS Owner
*/
bool dfs_owner;
/**
* twt_power_mgmt - Enable TWT based power management for P2P
*/
bool twt_power_mgmt;
/**
* comeback_after - Bootstrap request unauthorized for peer
*
* Ask to come back after this many TUs.
*/
u16 comeback_after;
/**
* cb_ctx - Context to use with callback functions
*/
@ -1136,6 +1232,19 @@ struct p2p_config {
int (*get_pref_freq_list)(void *ctx, int go,
unsigned int *len,
struct weighted_pcl *freq_list);
/**
* register_bootstrap_comeback - Register timeout to initiate bootstrap
* comeback request
* @ctx: Callback context from cb_ctx
* @addr: P2P Device Address to which comeback request is to be sent
* @comeback_after: Time in TUs after which comeback request is sent
*
* This function can be used to send comeback request after given
* timeout.
*/
void (*register_bootstrap_comeback)(void *ctx, const u8 *addr,
u16 comeback_after);
};
@ -1319,6 +1428,10 @@ void p2p_stop_listen(struct p2p_data *p2p);
* formation
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
* force_freq == 0)
* @oob_pw_id: OOB password identifier
* @p2p2: Device supports P2P2 features
* @bootstrap: Bootstrapping method requested for P2P2 provision discovery
* @password: P2P2 pairing password or %NULL for opportunistic method
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@ -1326,7 +1439,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id);
int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id,
bool p2p2, u16 bootstrap, const char *password);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@ -1344,6 +1458,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
* @force_ssid_len: Length of $force_ssid buffer
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
* force_freq == 0)
* @oob_pw_id: OOB password identifier
* @bootstrap: Bootstrapping method requested for P2P2 provision discovery
* @password: P2P2 pairing password or %NULL for opportunistic method
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@ -1354,7 +1471,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
unsigned int pref_freq, u16 oob_pw_id);
unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap,
const char *password);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@ -2429,5 +2547,8 @@ bool is_p2p_allow_6ghz(struct p2p_data *p2p);
void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size);
int p2p_channel_to_freq(int op_class, int channel);
struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
#endif /* P2P_H */

View file

@ -55,11 +55,24 @@ u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
{
/* Update P2P IE Length */
/* Update P2P/P2P2 IE Length */
*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
}
u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf)
{
u8 *len;
/* P2P2 IE header */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1); /* IE length to be filled */
wpabuf_put_be32(buf, P2P2_IE_VENDOR_TYPE);
wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header");
return len;
}
void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
{
/* P2P Capability */
@ -709,6 +722,111 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
}
void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p)
{
u8 *len;
u16 capability_info = 0;
/* P2P Capability Extension */
wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY_EXTENSION);
/* Length to be filled */
len = wpabuf_put(buf, 2);
if (!p2p->cfg->p2p_6ghz_disable)
capability_info |= P2P_PCEA_6GHZ;
if (p2p->cfg->reg_info)
capability_info |= P2P_PCEA_REG_INFO;
if (p2p->cfg->dfs_owner)
capability_info |= P2P_PCEA_DFS_OWNER;
if (p2p->cfg->pairing_config.pairing_capable)
capability_info |= P2P_PCEA_PAIRING_CAPABLE;
if (p2p->cfg->pairing_config.enable_pairing_setup)
capability_info |= P2P_PCEA_PAIRING_SETUP_ENABLED;
if (p2p->cfg->pairing_config.enable_pairing_cache)
capability_info |= P2P_PCEA_PMK_CACHING;
if (p2p->cfg->pairing_config.pasn_type)
capability_info |= P2P_PCEA_PASN_TYPE;
if (p2p->cfg->twt_power_mgmt)
capability_info |= P2P_PCEA_TWT_POWER_MGMT;
/* Field length is (n-1), n in octets */
capability_info |= (2 - 1) & P2P_PCEA_LEN_MASK;
wpabuf_put_le16(buf, capability_info);
if (capability_info & P2P_PCEA_REG_INFO)
wpabuf_put_u8(buf, p2p->cfg->reg_info);
if (capability_info & P2P_PCEA_PASN_TYPE)
wpabuf_put_u8(buf, p2p->cfg->pairing_config.pasn_type);
/* Update attribute length */
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
wpa_printf(MSG_DEBUG, "P2P: * Capability Extension info=0x%x",
capability_info);
}
void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie,
size_t cookie_len, int comeback_after)
{
u8 *len;
/* P2P Pairing and Bootstrapping methods */
wpabuf_put_u8(buf, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING);
/* Length to be filled */
len = wpabuf_put(buf, 2);
if (cookie && cookie_len) {
if (comeback_after)
wpabuf_put_le16(buf, comeback_after);
wpabuf_put_u8(buf, cookie_len);
wpabuf_put_data(buf, cookie, cookie_len);
}
wpabuf_put_le16(buf, bootstrap);
/* Update attribute length */
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
wpa_printf(MSG_DEBUG, "P2P: * Bootstrapping method=0x%x",
bootstrap);
}
void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p)
{
u8 *len;
struct p2p_id_key *dev_ik;
if (!p2p->cfg->pairing_config.pairing_capable ||
!p2p->cfg->pairing_config.enable_pairing_cache ||
!p2p->cfg->pairing_config.enable_pairing_verification)
return;
dev_ik = &p2p->pairing_info->dev_ik;
/* P2P DIRA */
wpabuf_put_u8(buf, P2P_ATTR_DEVICE_IDENTITY_RESOLUTION);
/* Length to be filled */
len = wpabuf_put(buf, 2);
wpabuf_put_u8(buf, dev_ik->cipher_version);
wpabuf_put_data(buf, dev_ik->dira_nonce, dev_ik->dira_nonce_len);
wpabuf_put_data(buf, dev_ik->dira_tag, dev_ik->dira_tag_len);
/* Update attribute length */
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
wpa_printf(MSG_DEBUG, "P2P: * DIRA");
}
static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
const char *val)
{

View file

@ -244,6 +244,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
config_method = WPS_CONFIG_PUSHBUTTON;
else if (dev->wps_method == WPS_P2PS)
config_method = WPS_CONFIG_P2PS;
else if (dev->p2p2 && dev->req_bootstrap_method)
config_method = WPS_NOT_READY;
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,

View file

@ -36,6 +36,26 @@ enum p2p_go_state {
REMOTE_GO
};
/**
* struct bootstrap_params - P2P Device bootstrap request parameters
*/
struct p2p_bootstrap_params {
/* Bootstrap method */
u16 bootstrap_method;
/* Status code */
enum p2p_status_code status;
/* Cookie for comeback */
u8 cookie[50];
/* Cookie length */
size_t cookie_len;
/* Comeback time in TUs after which receiver is requested to retry */
int comeback_after;
};
/**
* struct p2p_device - P2P Device data (internal to P2P module)
*/
@ -150,6 +170,18 @@ struct p2p_device {
int sd_pending_bcast_queries;
bool support_6ghz;
/* Supports P2P2 */
bool p2p2;
/* Requested bootstrap method */
u16 req_bootstrap_method;
/* Bootstrap parameters received from peer */
struct p2p_bootstrap_params *bootstrap_params;
/* Password for P2P2 GO negotiation */
char password[100];
};
struct p2p_sd_query {
@ -160,6 +192,39 @@ struct p2p_sd_query {
struct wpabuf *tlvs;
};
/* P2P Device Identity Key parameters */
struct p2p_id_key {
/* AKMP used for DevIK derviation */
int akmp;
/* Cipher version type */
int cipher_version;
/* Buffer to hold the DevIK */
u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
/* Length of DevIK */
size_t dik_len;
/* Nonce used in DIRA attribute */
u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN];
/* Length of nonce */
size_t dira_nonce_len;
/* Tag computed for nonce using NIK */
u8 dira_tag[DEVICE_IDENTITY_TAG_LEN];
/* Length of tag in octets */
size_t dira_tag_len;
};
struct p2p_pairing_info {
/* P2P device own address */
u8 own_addr[ETH_ALEN];
/* device capability to enable pairing setup */
bool enable_pairing_setup;
/* device capability to enable pairing cache */
bool enable_pairing_cache;
/* device supported bootstrapping */
u16 supported_bootstrap;
/* P2P Device Identity Key info */
struct p2p_id_key dev_ik;
};
/**
* struct p2p_data - P2P module data (internal to P2P module)
*/
@ -554,6 +619,8 @@ struct p2p_data {
bool p2p_6ghz_capable;
bool include_6ghz;
bool allow_6ghz;
struct p2p_pairing_info *pairing_info;
};
/**
@ -561,6 +628,7 @@ struct p2p_data {
*/
struct p2p_message {
struct wpabuf *p2p_attributes;
struct wpabuf *p2p2_attributes;
struct wpabuf *wps_attributes;
struct wpabuf *wfd_subelems;
@ -659,6 +727,12 @@ struct p2p_message {
const u8 *pref_freq_list;
size_t pref_freq_list_len;
const u8 *pcea_info;
size_t pcea_info_len;
const u8 *pbma_info;
size_t pbma_info_len;
};
@ -748,6 +822,7 @@ void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
u8 dialog_token);
u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf);
u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf);
void p2p_buf_add_status(struct wpabuf *buf, u8 status);
void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
struct p2p_device *peer);
@ -788,6 +863,10 @@ void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len,
const u8 *mask);
void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
const u8 *ssid, size_t ssid_len);
void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p);
void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie,
size_t cookie_len, int comeback_after);
void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p);
int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
int all_attr);
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
@ -826,14 +905,16 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
struct p2p_device *dev, struct p2p_message *msg);
/* p2p_pd.c */
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq);
void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq);
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int join, int force_freq);
void p2p_reset_pending_pd(struct p2p_data *p2p);
void p2ps_prov_free(struct p2p_data *p2p);
void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
struct p2p_device *dev);
/* p2p_invitation.c */
void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,

View file

@ -417,6 +417,26 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
msg->persistent_ssid_len));
break;
}
case P2P_ATTR_CAPABILITY_EXTENSION:
if (len < 2) {
wpa_printf(MSG_DEBUG, "P2P: Too short PCEA (length %d)",
len);
return -1;
}
msg->pcea_info = data;
msg->pcea_info_len = len;
wpa_printf(MSG_DEBUG, "P2P: * PCEA (length=%u)", len);
break;
case P2P_ATTR_PAIRING_AND_BOOTSTRAPPING:
if (len < 1) {
wpa_printf(MSG_DEBUG, "P2P: Too short PBMA (length %d)",
len);
return -1;
}
msg->pbma_info = data;
msg->pbma_info_len = len;
wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len);
break;
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
@ -573,6 +593,18 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
return -1;
}
msg->p2p2_attributes = ieee802_11_vendor_ie_concat(data, len,
P2P2_IE_VENDOR_TYPE);
if (msg->p2p2_attributes &&
p2p_parse_p2p_ie(msg->p2p2_attributes, msg)) {
wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P2 IE data");
if (msg->p2p2_attributes)
wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P2 IE data",
msg->p2p2_attributes);
p2p_parse_free(msg);
return -1;
}
#ifdef CONFIG_WIFI_DISPLAY
if (elems.wfd) {
msg->wfd_subelems = ieee802_11_vendor_ie_concat(
@ -647,6 +679,8 @@ void p2p_parse_free(struct p2p_message *msg)
{
wpabuf_free(msg->p2p_attributes);
msg->p2p_attributes = NULL;
wpabuf_free(msg->p2p2_attributes);
msg->p2p2_attributes = NULL;
wpabuf_free(msg->wps_attributes);
msg->wps_attributes = NULL;
#ifdef CONFIG_WIFI_DISPLAY

File diff suppressed because it is too large Load diff

View file

@ -192,6 +192,14 @@ int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies,
}
void pasn_set_noauth(struct pasn_data *pasn, bool noauth)
{
if (!pasn)
return;
pasn->noauth = noauth;
}
int pasn_get_akmp(struct pasn_data *pasn)
{
if (!pasn)

View file

@ -174,7 +174,8 @@ int wpa_pasn_auth_tx_status(struct pasn_data *pasn,
/* Responder */
int handle_auth_pasn_1(struct pasn_data *pasn,
const u8 *own_addr, const u8 *peer_addr,
const struct ieee80211_mgmt *mgmt, size_t len);
const struct ieee80211_mgmt *mgmt, size_t len,
bool reject);
int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
const u8 *peer_addr,
const struct ieee80211_mgmt *mgmt, size_t len);
@ -207,6 +208,7 @@ void pasn_set_responder_pmksa(struct pasn_data *pasn,
int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt);
/* Responder */
void pasn_set_noauth(struct pasn_data *pasn, bool noauth);
void pasn_set_password(struct pasn_data *pasn, const char *password);
void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt);
void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise);

View file

@ -597,7 +597,8 @@ fail:
int handle_auth_pasn_1(struct pasn_data *pasn,
const u8 *own_addr, const u8 *peer_addr,
const struct ieee80211_mgmt *mgmt, size_t len)
const struct ieee80211_mgmt *mgmt, size_t len,
bool reject)
{
struct ieee802_11_elems elems;
struct wpa_ie_data rsn_data;
@ -616,6 +617,12 @@ int handle_auth_pasn_1(struct pasn_data *pasn,
if (!groups)
groups = default_groups;
if (reject) {
wpa_printf(MSG_DEBUG, "PASN: Received Rejection");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto send_resp;
}
if (ieee802_11_parse_elems(mgmt->u.auth.variable,
len - offsetof(struct ieee80211_mgmt,
u.auth.variable),

View file

@ -531,7 +531,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
size_t mic_len, hdrlen, rlen, extra_len = 0;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
u8 *rsn_ie_buf = NULL, *buf2 = NULL;
u16 key_info;
#ifdef CONFIG_TESTING_OPTIONS
size_t pad_len = 0;
@ -581,6 +581,37 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
}
#endif /* CONFIG_IEEE80211R */
if (sm->rsn_override != RSN_OVERRIDE_NOT_USED) {
u8 *pos;
buf2 = os_malloc(wpa_ie_len + 2 + 4 + 1);
if (!buf2) {
os_free(rsn_ie_buf);
return -1;
}
os_memcpy(buf2, wpa_ie, wpa_ie_len);
pos = buf2 + wpa_ie_len;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + 1;
WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
pos += 4;
if (sm->rsn_override == RSN_OVERRIDE_RSNE) {
*pos++ = RSN_SELECTION_RSNE;
} else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
*pos++ = RSN_SELECTION_RSNE_OVERRIDE;
} else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
*pos++ = RSN_SELECTION_RSNE_OVERRIDE_2;
} else {
os_free(rsn_ie_buf);
os_free(buf2);
return -1;
}
wpa_ie = buf2;
wpa_ie_len += 2 + 4 + 1;
}
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
#ifdef CONFIG_TESTING_OPTIONS
@ -601,6 +632,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
os_free(buf2);
return -1;
}
@ -633,6 +665,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len + extra_len);
os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
os_free(rsn_ie_buf);
os_free(buf2);
#ifdef CONFIG_TESTING_OPTIONS
if (sm->test_eapol_m2_elems) {
os_memcpy(key_mic + mic_len + 2 + wpa_ie_len,
@ -990,6 +1023,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
"WPA: Failed to get random data for SNonce");
goto failed;
}
if (wpa_sm_rsn_overriding_supported(sm))
rsn_set_snonce_cookie(sm->snonce);
sm->renew_snonce = 0;
wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
sm->snonce, WPA_NONCE_LEN);
@ -2193,6 +2228,68 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1;
}
if (sm->proto == WPA_PROTO_RSN && wpa_sm_rsn_overriding_supported(sm)) {
if ((sm->ap_rsne_override && !ie->rsne_override) ||
(!sm->ap_rsne_override && ie->rsne_override) ||
(sm->ap_rsne_override && ie->rsne_override &&
(sm->ap_rsne_override_len != ie->rsne_override_len ||
os_memcmp(sm->ap_rsne_override, ie->rsne_override,
sm->ap_rsne_override_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: RSNE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
wpa_hexdump(MSG_INFO,
"RSNE Override element in Beacon/ProbeResp",
sm->ap_rsne_override,
sm->ap_rsne_override_len);
wpa_hexdump(MSG_INFO,
"RSNE Override element in EAPOL-Key msg 3/4",
ie->rsne_override, ie->rsne_override_len);
wpa_sm_deauthenticate(sm,
WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
if ((sm->ap_rsne_override_2 && !ie->rsne_override_2) ||
(!sm->ap_rsne_override_2 && ie->rsne_override_2) ||
(sm->ap_rsne_override_2 && ie->rsne_override_2 &&
(sm->ap_rsne_override_2_len != ie->rsne_override_2_len ||
os_memcmp(sm->ap_rsne_override_2, ie->rsne_override_2,
sm->ap_rsne_override_2_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: RSNE Override 2 element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
wpa_hexdump(MSG_INFO,
"RSNE Override 2 element in Beacon/ProbeResp",
sm->ap_rsne_override_2,
sm->ap_rsne_override_2_len);
wpa_hexdump(MSG_INFO,
"RSNE Override 2 element in EAPOL-Key msg 3/4",
ie->rsne_override_2, ie->rsne_override_2_len);
wpa_sm_deauthenticate(sm,
WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
if ((sm->ap_rsnxe_override && !ie->rsnxe_override) ||
(!sm->ap_rsnxe_override && ie->rsnxe_override) ||
(sm->ap_rsnxe_override && ie->rsnxe_override &&
(sm->ap_rsnxe_override_len != ie->rsnxe_override_len ||
os_memcmp(sm->ap_rsnxe_override, ie->rsnxe_override,
sm->ap_rsnxe_override_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: RSNXE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
wpa_hexdump(MSG_INFO,
"RSNXE Override element in Beacon/ProbeResp",
sm->ap_rsnxe_override,
sm->ap_rsnxe_override_len);
wpa_hexdump(MSG_INFO,
"RSNXE Override element in EAPOL-Key msg 3/4",
ie->rsnxe_override, ie->rsnxe_override_len);
wpa_sm_deauthenticate(sm,
WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
}
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@ -2339,10 +2436,14 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id,
const u8 *link_kde,
size_t link_kde_len)
size_t link_kde_len,
const u8 *rsn_override_link_kde,
size_t rsn_override_link_kde_len)
{
size_t rsne_len = 0, rsnxe_len = 0;
const u8 *rsne = NULL, *rsnxe = NULL;
size_t rsne_len = 0, rsnxe_len = 0, rsnoe_len = 0, rsno2e_len = 0,
rsnxoe_len = 0;
const u8 *rsne = NULL, *rsnxe = NULL, *rsnoe = NULL, *rsno2e = NULL,
*rsnxoe = NULL;
if (!link_kde ||
link_kde_len < RSN_MLO_LINK_KDE_LINK_MAC_INDEX + ETH_ALEN) {
@ -2403,14 +2504,14 @@ static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id,
sm->mlo.links[link_id].ap_rsne_len,
rsne, rsne_len)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN MLO: IE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
"RSN MLO: RSNE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
link_id);
wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
sm->mlo.links[link_id].ap_rsne,
sm->mlo.links[link_id].ap_rsne_len);
wpa_hexdump(MSG_INFO, "RSNE in EAPOL-Key msg 3/4",
rsne, rsne_len);
return -1;
goto fail;
}
if ((sm->mlo.links[link_id].ap_rsnxe && !rsnxe) ||
@ -2427,11 +2528,89 @@ static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id,
sm->mlo.links[link_id].ap_rsnxe_len);
wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
rsnxe, rsnxe_len);
wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
goto fail;
}
if (!wpa_sm_rsn_overriding_supported(sm))
return 0;
if (rsn_override_link_kde) {
rsnoe = get_vendor_ie(rsn_override_link_kde + 1,
rsn_override_link_kde_len - 1,
RSNE_OVERRIDE_IE_VENDOR_TYPE);
if (rsnoe)
rsnoe_len = 2 + rsnoe[1];
rsno2e = get_vendor_ie(rsn_override_link_kde + 1,
rsn_override_link_kde_len - 1,
RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
if (rsno2e)
rsno2e_len = 2 + rsno2e[1];
rsnxoe = get_vendor_ie(rsn_override_link_kde + 1,
rsn_override_link_kde_len - 1,
RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (rsnxoe)
rsnxoe_len = 2 + rsnxoe[1];
}
if ((sm->mlo.links[link_id].ap_rsnoe && !rsnoe) ||
(!sm->mlo.links[link_id].ap_rsnoe && rsnoe) ||
(sm->mlo.links[link_id].ap_rsnoe && rsnoe &&
wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
sm->mlo.links[link_id].ap_rsnoe,
sm->mlo.links[link_id].ap_rsnoe_len,
rsnoe, rsnoe_len))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN MLO: RSNOE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
link_id);
wpa_hexdump(MSG_INFO, "RSNOE in Beacon/ProbeResp",
sm->mlo.links[link_id].ap_rsnoe,
sm->mlo.links[link_id].ap_rsnoe_len);
wpa_hexdump(MSG_INFO, "RSNOE in EAPOL-Key msg 3/4",
rsnoe, rsnoe_len);
goto fail;
}
if ((sm->mlo.links[link_id].ap_rsno2e && !rsno2e) ||
(!sm->mlo.links[link_id].ap_rsno2e && rsno2e) ||
(sm->mlo.links[link_id].ap_rsno2e && rsno2e &&
wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
sm->mlo.links[link_id].ap_rsno2e,
sm->mlo.links[link_id].ap_rsno2e_len,
rsno2e, rsno2e_len))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN MLO: RSNO2E in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
link_id);
wpa_hexdump(MSG_INFO, "RSNO2E in Beacon/ProbeResp",
sm->mlo.links[link_id].ap_rsno2e,
sm->mlo.links[link_id].ap_rsno2e_len);
wpa_hexdump(MSG_INFO, "RSNOE in EAPOL-Key msg 3/4",
rsno2e, rsno2e_len);
goto fail;
}
if ((sm->mlo.links[link_id].ap_rsnxoe && !rsnxoe) ||
(!sm->mlo.links[link_id].ap_rsnxoe && rsnxoe) ||
(sm->mlo.links[link_id].ap_rsnxoe && rsnxoe &&
(sm->mlo.links[link_id].ap_rsnxoe_len != rsnxoe_len ||
os_memcmp(sm->mlo.links[link_id].ap_rsnxoe, rsnxoe,
sm->mlo.links[link_id].ap_rsnxoe_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN MLO: RSNXOE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4 for link ID %u",
link_id);
wpa_hexdump(MSG_INFO, "RSNXOE in Beacon/ProbeResp",
sm->mlo.links[link_id].ap_rsnxoe,
sm->mlo.links[link_id].ap_rsnxoe_len);
wpa_hexdump(MSG_INFO, "RSNXOE in EAPOL-Key msg 3/4",
rsnxoe, rsnxoe_len);
goto fail;
}
return 0;
fail:
wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
@ -2599,8 +2778,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (!(sm->mlo.req_links & BIT(i)))
continue;
if (wpa_supplicant_validate_link_kde(sm, i, ie.mlo_link[i],
ie.mlo_link_len[i]) < 0)
if (wpa_supplicant_validate_link_kde(
sm, i, ie.mlo_link[i], ie.mlo_link_len[i],
ie.rsn_override_link[i],
ie.rsn_override_link_len[i]) < 0)
goto failed;
if (!(sm->mlo.valid_links & BIT(i)))
@ -4173,9 +4354,15 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
os_free(sm->ap_rsnxe);
os_free(sm->ap_rsne_override);
os_free(sm->ap_rsne_override_2);
os_free(sm->ap_rsnxe_override);
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
os_free(sm->mlo.links[i].ap_rsne);
os_free(sm->mlo.links[i].ap_rsnxe);
os_free(sm->mlo.links[i].ap_rsnoe);
os_free(sm->mlo.links[i].ap_rsno2e);
os_free(sm->mlo.links[i].ap_rsnxoe);
}
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
@ -4578,6 +4765,69 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
}
sm->mlo.links[i].ap_rsnxe_len = len;
}
ie = mlo->links[i].ap_rsnoe;
len = mlo->links[i].ap_rsnoe_len;
os_free(sm->mlo.links[i].ap_rsnoe);
if (!ie || len == 0) {
if (sm->mlo.links[i].ap_rsnoe)
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing MLO link[%u] AP RSNOE",
i);
sm->mlo.links[i].ap_rsnoe = NULL;
sm->mlo.links[i].ap_rsnoe_len = 0;
} else {
wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNOE",
ie, len);
sm->mlo.links[i].ap_rsnoe = os_memdup(ie, len);
if (!sm->mlo.links[i].ap_rsnoe) {
sm->mlo.links[i].ap_rsnoe_len = 0;
return -1;
}
sm->mlo.links[i].ap_rsnoe_len = len;
}
ie = mlo->links[i].ap_rsno2e;
len = mlo->links[i].ap_rsno2e_len;
os_free(sm->mlo.links[i].ap_rsno2e);
if (!ie || len == 0) {
if (sm->mlo.links[i].ap_rsno2e)
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing MLO link[%u] AP RSNO2E",
i);
sm->mlo.links[i].ap_rsno2e = NULL;
sm->mlo.links[i].ap_rsno2e_len = 0;
} else {
wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNO2E",
ie, len);
sm->mlo.links[i].ap_rsno2e = os_memdup(ie, len);
if (!sm->mlo.links[i].ap_rsno2e) {
sm->mlo.links[i].ap_rsno2e_len = 0;
return -1;
}
sm->mlo.links[i].ap_rsno2e_len = len;
}
ie = mlo->links[i].ap_rsnxoe;
len = mlo->links[i].ap_rsnxoe_len;
os_free(sm->mlo.links[i].ap_rsnxoe);
if (!ie || len == 0) {
if (sm->mlo.links[i].ap_rsnxoe)
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing MLO link[%u] AP RSNXOE",
i);
sm->mlo.links[i].ap_rsnxoe = NULL;
sm->mlo.links[i].ap_rsnxoe_len = 0;
} else {
wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNXOE",
ie, len);
sm->mlo.links[i].ap_rsnxoe = os_memdup(ie, len);
if (!sm->mlo.links[i].ap_rsnxoe) {
sm->mlo.links[i].ap_rsnxoe_len = 0;
return -1;
}
sm->mlo.links[i].ap_rsnxoe_len = len;
}
}
return 0;
@ -4737,6 +4987,12 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SSID_PROTECTION:
sm->ssid_protection = value;
break;
case WPA_PARAM_RSN_OVERRIDE:
sm->rsn_override = value;
break;
case WPA_PARAM_RSN_OVERRIDE_SUPPORT:
sm->rsn_override_support = value;
break;
default:
break;
}
@ -4745,6 +5001,23 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
}
static const u8 * wpa_sm_get_ap_rsne(struct wpa_sm *sm, size_t *len)
{
if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
*len = sm->ap_rsne_override_len;
return sm->ap_rsne_override;
}
if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
*len = sm->ap_rsne_override_2_len;
return sm->ap_rsne_override_2;
}
*len = sm->ap_rsn_ie_len;
return sm->ap_rsn_ie;
}
/**
* wpa_sm_get_status - Get WPA state machine
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@ -4762,6 +5035,10 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
{
char *pos = buf, *end = buf + buflen;
int ret;
const u8 *rsne;
size_t rsne_len;
rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
ret = os_snprintf(pos, end - pos,
"pairwise_cipher=%s\n"
@ -4783,10 +5060,10 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
}
#endif /* CONFIG_DPP2 */
if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
if (sm->mfp != NO_MGMT_FRAME_PROTECTION && rsne) {
struct wpa_ie_data rsn;
if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
>= 0 &&
if (wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
rsn.capabilities & (WPA_CAPABILITY_MFPR |
WPA_CAPABILITY_MFPC)) {
ret = os_snprintf(pos, end - pos, "pmf=%d\n"
@ -4808,11 +5085,15 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int wpa_sm_pmf_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
const u8 *rsne;
size_t rsne_len;
if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !rsne)
return 0;
if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
if (wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
return 1;
@ -4820,6 +5101,17 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm)
{
const u8 *rsne;
size_t rsne_len;
rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
return sm->rsn_override_support && rsne;
}
int wpa_sm_ext_key_id(struct wpa_sm *sm)
{
return sm ? sm->ext_key_id : 0;
@ -4835,12 +5127,14 @@ int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
const u8 *rsne;
size_t rsne_len;
if (!sm->ocv || !sm->ap_rsn_ie)
rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
if (!sm->ocv || !rsne)
return 0;
return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
&rsn) >= 0 &&
return wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
(rsn.capabilities & WPA_CAPABILITY_OCVC);
}
@ -5121,6 +5415,81 @@ int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
}
int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len)
{
if (!sm)
return -1;
os_free(sm->ap_rsne_override);
if (!ie || len == 0) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing AP RSNE Override element");
sm->ap_rsne_override = NULL;
sm->ap_rsne_override_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNE Override element",
ie, len);
sm->ap_rsne_override = os_memdup(ie, len);
if (!sm->ap_rsne_override)
return -1;
sm->ap_rsne_override_len = len;
}
return 0;
}
int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie, size_t len)
{
if (!sm)
return -1;
os_free(sm->ap_rsne_override_2);
if (!ie || len == 0) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing AP RSNE Override 2 element");
sm->ap_rsne_override_2 = NULL;
sm->ap_rsne_override_2_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNE Override 2 element",
ie, len);
sm->ap_rsne_override_2 = os_memdup(ie, len);
if (!sm->ap_rsne_override_2)
return -1;
sm->ap_rsne_override_2_len = len;
}
return 0;
}
int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len)
{
if (!sm)
return -1;
os_free(sm->ap_rsnxe_override);
if (!ie || len == 0) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Clearing AP RSNXE Override element");
sm->ap_rsnxe_override = NULL;
sm->ap_rsnxe_override_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNXE Override element",
ie, len);
sm->ap_rsnxe_override = os_memdup(ie, len);
if (!sm->ap_rsnxe_override)
return -1;
sm->ap_rsnxe_override_len = len;
}
return 0;
}
/**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init()

View file

@ -137,6 +137,15 @@ enum wpa_sm_conf_params {
WPA_PARAM_ENCRYPT_EAPOL_M4,
WPA_PARAM_FT_PREPEND_PMKID,
WPA_PARAM_SSID_PROTECTION,
WPA_PARAM_RSN_OVERRIDE,
WPA_PARAM_RSN_OVERRIDE_SUPPORT,
};
enum wpa_rsn_override {
RSN_OVERRIDE_NOT_USED,
RSN_OVERRIDE_RSNE,
RSN_OVERRIDE_RSNE_OVERRIDE,
RSN_OVERRIDE_RSNE_OVERRIDE_2,
};
struct rsn_supp_config {
@ -160,8 +169,9 @@ struct rsn_supp_config {
struct wpa_sm_link {
u8 addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u8 *ap_rsne, *ap_rsnxe;
size_t ap_rsne_len, ap_rsnxe_len;
u8 *ap_rsne, *ap_rsnxe, *ap_rsnoe, *ap_rsno2e, *ap_rsnxoe;
size_t ap_rsne_len, ap_rsnxe_len, ap_rsnoe_len, ap_rsno2e_len,
ap_rsnxoe_len;;
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
struct wpa_igtk igtk;
@ -204,6 +214,9 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@ -348,6 +361,24 @@ static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
return -1;
}
static inline int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie,
size_t len)
{
return -1;
}
static inline int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie,
size_t len)
{
return -1;
}
static inline int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie,
size_t len)
{
return -1;
}
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;

View file

@ -120,6 +120,9 @@ struct wpa_sm {
size_t assoc_rsnxe_len;
u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
u8 *ap_rsne_override, *ap_rsne_override_2, *ap_rsnxe_override;
size_t ap_rsne_override_len, ap_rsne_override_2_len,
ap_rsnxe_override_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
@ -229,6 +232,9 @@ struct wpa_sm {
bool wmm_enabled;
bool driver_bss_selection;
bool ft_prepend_pmkid;
bool rsn_override_support;
enum wpa_rsn_override rsn_override;
};
@ -542,5 +548,6 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm);
#endif /* WPA_I_H */

View file

@ -33,8 +33,15 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
else
return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
wpa_ie[1] >= 4 &&
WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE)
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
wpa_ie[1] >= 4 &&
WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE)
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
}

View file

@ -77,9 +77,6 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
eloop_timeout_poll_handler timeout_poll_cb;
eloop_poll_handler poll_cb;
size_t count; /* sum of all table counts */
#ifdef CONFIG_ELOOP_POLL
size_t max_pollfd_map; /* number of pollfds_map currently allocated */
@ -1124,12 +1121,6 @@ void eloop_run(void)
os_reltime_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
}
if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
timeout = (void *)1;
if (timeout) {
#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
timeout_ms = tv.sec * 1000 + tv.usec / 1000;
#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
@ -1199,8 +1190,7 @@ void eloop_run(void)
eloop.exceptions.changed = 0;
eloop_process_pending_signals();
if (eloop.poll_cb)
eloop.poll_cb();
/* check if some registered timeouts have occurred */
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
@ -1262,14 +1252,6 @@ out:
return;
}
int eloop_register_cb(eloop_poll_handler poll_cb,
eloop_timeout_poll_handler timeout_cb)
{
eloop.poll_cb = poll_cb;
eloop.timeout_poll_cb = timeout_cb;
return 0;
}
void eloop_terminate(void)
{

View file

@ -65,9 +65,6 @@ typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx);
*/
typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
typedef void (*eloop_poll_handler)(void);
/**
* eloop_init() - Initialize global event loop data
* Returns: 0 on success, -1 on failure
@ -76,9 +73,6 @@ typedef void (*eloop_poll_handler)(void);
*/
int eloop_init(void);
int eloop_register_cb(eloop_poll_handler poll_cb,
eloop_timeout_poll_handler timeout_cb);
/**
* eloop_register_read_sock - Register handler for read events
* @sock: File descriptor number for the socket
@ -326,8 +320,6 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler,
*/
int eloop_sock_requeue(void);
void eloop_add_uloop(void);
/**
* eloop_run - Start the event loop
*

View file

@ -1,64 +0,0 @@
#include <libubox/uloop.h>
#include "includes.h"
#include "common.h"
#include "eloop.h"
static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
{
}
static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
{
unsigned int changed = events ^ fd->flags;
if (changed & ULOOP_READ) {
if (events & ULOOP_READ)
eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
else
eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
}
if (changed & ULOOP_WRITE) {
if (events & ULOOP_WRITE)
eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
else
eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
}
}
static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
{
struct os_reltime tv_uloop;
int timeout_ms = uloop_get_next_timeout();
if (timeout_ms < 0)
return false;
tv_uloop.sec = timeout_ms / 1000;
tv_uloop.usec = (timeout_ms % 1000) * 1000;
if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
*tv = tv_uloop;
return true;
}
return false;
}
static void uloop_poll_handler(void)
{
uloop_run_timeout(0);
}
void eloop_add_uloop(void)
{
static bool init_done = false;
if (!init_done) {
uloop_init();
uloop_fd_set_cb = eloop_uloop_fd_cb;
init_done = true;
}
eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
}

View file

@ -15,6 +15,7 @@ import wpaspy
import remotehost
import utils
import subprocess
from remotectrl import RemoteCtrl
logger = logging.getLogger()
hapd_ctrl = '/var/run/hostapd'
@ -28,12 +29,18 @@ class HostapdGlobal:
try:
hostname = apdev['hostname']
port = apdev['port']
if 'remote_cli' in apdev:
remote_cli = apdev['remote_cli']
else:
remote_cli = False
except:
hostname = None
port = 8878
remote_cli = False
self.host = remotehost.Host(hostname)
self.hostname = hostname
self.port = port
self.remote_cli = remote_cli
if hostname is None:
global_ctrl = hapd_global
if global_ctrl_override:
@ -42,9 +49,17 @@ class HostapdGlobal:
self.mon = wpaspy.Ctrl(global_ctrl)
self.dbg = ""
else:
self.ctrl = wpaspy.Ctrl(hostname, port)
self.mon = wpaspy.Ctrl(hostname, port)
self.dbg = hostname + "/" + str(port)
if remote_cli:
global_ctrl = hapd_global
if global_ctrl_override:
global_ctrl = global_ctrl_override
self.ctrl = RemoteCtrl(global_ctrl, port, hostname=hostname)
self.mon = RemoteCtrl(global_ctrl, port, hostname=hostname)
self.dbg = hostname + "/global"
else:
self.ctrl = wpaspy.Ctrl(hostname, port)
self.mon = wpaspy.Ctrl(hostname, port)
self.dbg = hostname + "/" + str(port)
self.mon.attach()
def cmd_execute(self, cmd_array, shell=False):
@ -119,6 +134,9 @@ class HostapdGlobal:
if self.hostname is None:
return None
if self.remote_cli:
return None
res = self.request("INTERFACES ctrl")
lines = res.splitlines()
found = False
@ -147,17 +165,26 @@ class HostapdGlobal:
class Hostapd:
def __init__(self, ifname, bssidx=0, hostname=None, ctrl=hapd_ctrl,
port=8877):
port=8877, remote_cli=False, link=None):
self.hostname = hostname
self.host = remotehost.Host(hostname, ifname)
self.ifname = ifname
self.remote_cli = remote_cli
if hostname is None:
if link is not None:
ifname = ifname + "_link" + str(link)
self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname))
self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname))
self.dbg = ifname
else:
self.ctrl = wpaspy.Ctrl(hostname, port)
self.mon = wpaspy.Ctrl(hostname, port)
if remote_cli:
self.ctrl = RemoteCtrl(ctrl, port, hostname=hostname,
ifname=ifname)
self.mon = RemoteCtrl(ctrl, port, hostname=hostname,
ifname=ifname)
else:
self.ctrl = wpaspy.Ctrl(hostname, port)
self.mon = wpaspy.Ctrl(hostname, port)
self.dbg = hostname + "/" + ifname
self.mon.attach()
self.bssid = None
@ -638,22 +665,31 @@ def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30,
try:
hostname = apdev['hostname']
port = apdev['port']
logger.info("Starting AP " + hostname + "/" + port + " " + ifname)
if 'remote_cli' in apdev:
remote_cli = apdev['remote_cli']
else:
remote_cli = False
if 'global_ctrl_override' in apdev:
global_ctrl_override = apdev['global_ctrl_override']
logger.info("Starting AP " + hostname + "/" + port + " " + ifname + " remote_cli " + str(remote_cli))
except:
logger.info("Starting AP " + ifname)
hostname = None
port = 8878
remote_cli = False
else:
ifname = apdev
logger.info("Starting AP " + ifname + " (old add_ap argument type)")
hostname = None
port = 8878
remote_cli = False
hapd_global = HostapdGlobal(apdev,
global_ctrl_override=global_ctrl_override)
hapd_global.remove(ifname)
hapd_global.add(ifname, driver=driver)
port = hapd_global.get_ctrl_iface_port(ifname)
hapd = Hostapd(ifname, hostname=hostname, port=port)
hapd = Hostapd(ifname, hostname=hostname, port=port,
remote_cli=remote_cli)
if not hapd.ping():
raise Exception("Could not ping hostapd")
hapd.set_defaults(set_channel=set_channel)
@ -688,17 +724,22 @@ def add_bss(apdev, ifname, confname, ignore_error=False):
try:
hostname = apdev['hostname']
port = apdev['port']
logger.info("Starting BSS " + hostname + "/" + port + " phy=" + phy + " ifname=" + ifname)
if 'remote_cli' in apdev:
remote_cli = apdev['remote_cli']
else:
remote_cli = False
logger.info("Starting BSS " + hostname + "/" + port + " phy=" + phy + " ifname=" + ifname + " remote_cli=" + str(remote_cli))
except:
logger.info("Starting BSS phy=" + phy + " ifname=" + ifname)
hostname = None
port = 8878
remote_cli = False
hapd_global = HostapdGlobal(apdev)
confname = cfg_file(apdev, confname, ifname)
hapd_global.send_file(confname, confname)
hapd_global.add_bss(phy, confname, ignore_error)
port = hapd_global.get_ctrl_iface_port(ifname)
hapd = Hostapd(ifname, hostname=hostname, port=port)
hapd = Hostapd(ifname, hostname=hostname, port=port, remote_cli=remote_cli)
if not hapd.ping():
raise Exception("Could not ping hostapd")
return hapd
@ -708,22 +749,27 @@ def add_iface(apdev, confname):
try:
hostname = apdev['hostname']
port = apdev['port']
logger.info("Starting interface " + hostname + "/" + port + " " + ifname)
if 'remote_cli' in apdev:
remote_cli = apdev['remote_cli']
else:
remote_cli = False
logger.info("Starting interface " + hostname + "/" + port + " " + ifname + "remote_cli=" + str(remote_cli))
except:
logger.info("Starting interface " + ifname)
hostname = None
port = 8878
remote_cli = False
hapd_global = HostapdGlobal(apdev)
confname = cfg_file(apdev, confname, ifname)
hapd_global.send_file(confname, confname)
hapd_global.add_iface(ifname, confname)
port = hapd_global.get_ctrl_iface_port(ifname)
hapd = Hostapd(ifname, hostname=hostname, port=port)
hapd = Hostapd(ifname, hostname=hostname, port=port, remote_cli=remote_cli)
if not hapd.ping():
raise Exception("Could not ping hostapd")
return hapd
def add_mld_link(apdev, params):
def add_mld_link(apdev, link_id, params):
if isinstance(apdev, dict):
ifname = apdev['ifname']
try:
@ -749,7 +795,8 @@ def add_mld_link(apdev, params):
if str(e) == "Could not add hostapd link":
raise utils.HwsimSkip("No MLO support in hostapd")
port = hapd_global.get_ctrl_iface_port(ifname)
hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port)
hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port,
link=link_id)
if not hapd.ping():
raise Exception("Could not ping hostapd")
return hapd
@ -1023,9 +1070,6 @@ def cfg_mld_link_file(ifname, params):
fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-')
f = os.fdopen(fd, 'w')
if idx != 0:
ctrl_iface="/var/run/hostapd_%d" % idx
f.write("ctrl_interface=%s\n" % ctrl_iface)
f.write("driver=nl80211\n")
f.write("ieee80211n=1\n")

36
tests/hwsim/mld.py Normal file
View file

@ -0,0 +1,36 @@
# Python class for controlling Multi Link Device
# Copyright (c) 2024, 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 logging
import wpaspy
logger = logging.getLogger()
hapd_ctrl = '/var/run/hostapd'
class MultiLinkDevice:
def __init__(self, ifname, ctrl=hapd_ctrl, port=8877):
self.ifname = ifname
self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname))
self.dbg = ifname
def close_ctrl(self):
self.ctrl.close()
self.ctrl = None
def request(self, cmd):
logger.debug(self.dbg + ": MLD CTRL: " + cmd)
return self.ctrl.request(cmd)
def ping(self):
return "PONG" in self.request("PING")
def get_mld_obj(ifname, ctrl=hapd_ctrl, port=8877):
mld = MultiLinkDevice(ifname, ctrl, port)
if not mld.ping():
raise Exception("Could not ping MLD %s" % ifname)
return mld

92
tests/hwsim/remotectrl.py Normal file
View file

@ -0,0 +1,92 @@
#!/usr/bin/python
#
# wpa_supplicant/hostapd control interface using Python
# Copyright (c) 2024, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
from wpaspy import Ctrl
import remotehost
class RemoteCtrl(Ctrl):
def __init__(self, path, port=9877, hostname=None, ifname=None):
self.started = False
self.attached = False
self.path = path
self.port = port
self.ifname = ifname
self.hostname = hostname
self.proc = None
self.host = remotehost.Host(hostname)
self.started = True
def __del__(self):
self.close()
def close(self):
if self.attached:
try:
self.detach()
except Exception as e:
# Need to ignore this allow the socket to be closed
self.attached = False
pass
if self.host and self.started:
self.started = False
def request(self, cmd, timeout=10):
if self.host:
cmd = '\'' + cmd + '\''
if self.ifname:
_cmd = ['wpa_cli', '-p', self.path, '-i', self.ifname, "raw " + cmd]
else:
_cmd = ['wpa_cli', '-g', self.path, "raw " + cmd]
status, buf = self.host.execute(_cmd)
return buf
def attach(self):
if self.attached:
return
if self.host:
if self.ifname:
_cmd = [ "wpa_cli", "-p", self.path, "-i", self.ifname ]
else:
_cmd = [ "wpa_cli", '-g', self.path]
self.proc = self.host.proc_run(_cmd)
self.attached = True
def detach(self):
if not self.attached:
return
if self.hostname and self.proc:
self.request("DETACH")
self.request("QUIT")
self.host.proc_stop(self.proc)
self.attached = False
self.proc = None
def terminate(self):
if self.attached:
try:
self.detach()
except Exception as e:
# Need to ignore this to allow the socket to be closed
self.attached = False
self.request("TERMINATE")
self.close()
def pending(self, timeout=0):
if self.host and self.proc:
return self.host.proc_pending(self.proc, timeout=timeout)
return False
def recv(self):
if self.host and self.proc:
res = self.host.proc_read(self.proc)
return res
return ""

View file

@ -83,7 +83,10 @@ class Host():
if self.host is None:
return self.local_execute(command)
cmd = ["ssh", self.user + "@" + self.host, ' '.join(command)]
if self.user:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(command)]
else:
cmd = ["ssh", self.host, ' '.join(command)]
_cmd = self.name + " execute: " + ' '.join(cmd)
logger.debug(_cmd)
err = tempfile.TemporaryFile()
@ -114,7 +117,10 @@ class Host():
if self.host is None:
cmd = _command
else:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
if self.user:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
else:
cmd = ["ssh", self.host, ' '.join(_command)]
_cmd = self.name + " thread_run: " + ' '.join(cmd)
logger.debug(_cmd)
t = threading.Thread(target=execute_thread, name=filename, args=(cmd, res))
@ -174,7 +180,10 @@ class Host():
_command = [filename] + command
if self.host:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
if self.user:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
else:
cmd = ["ssh", self.host, ' '.join(_command)]
else:
cmd = _command
@ -261,12 +270,18 @@ class Host():
def get_logs(self, local_log_dir=None):
for log in self.logs:
if local_log_dir:
self.local_execute(["scp", self.user + "@[" + self.host + "]:" + log, local_log_dir])
if self.user:
self.local_execute(["scp", self.user + "@[" + self.host + "]:" + log, local_log_dir])
else:
self.local_execute(["scp", "[" + self.host + "]:" + log, local_log_dir])
self.execute(["rm", log])
del self.logs[:]
def send_file(self, src, dst):
if self.host is None:
return
self.local_execute(["scp", src,
self.user + "@[" + self.host + "]:" + dst])
if self.user:
self.local_execute(["scp", src,
self.user + "@[" + self.host + "]:" + dst])
else:
self.local_execute(["scp", src, "[" + self.host + "]:" + dst])

View file

@ -374,12 +374,12 @@ def test_ap_ft_vlan(dev, apdev):
params = ft_params1(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, conndev="brvlan1")
if "[WPA2-FT/PSK-CCMP]" not in dev[0].request("SCAN_RESULTS"):
@ -413,13 +413,13 @@ def test_ap_ft_vlan_disconnected(dev, apdev):
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
params['ft_psk_generate_local'] = "1"
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2a(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
params['ft_psk_generate_local'] = "1"
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, conndev="brvlan1")
if "[WPA2-FT/PSK-CCMP]" not in dev[0].request("SCAN_RESULTS"):
@ -437,11 +437,11 @@ def test_ap_ft_vlan_2(dev, apdev):
params = ft_params1(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, conndev="brvlan1",
force_initial_conn_to_first_ap=True)
@ -520,12 +520,12 @@ def test_ap_ft_many_vlan(dev, apdev):
params = ft_params1(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, roams=50,
conndev="brvlan1")
@ -862,11 +862,11 @@ def test_ap_ft_vlan_over_ds(dev, apdev):
params = ft_params1(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
dev[0].flush_scan_cache()
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
@ -900,11 +900,11 @@ def test_ap_ft_vlan_over_ds_many(dev, apdev):
params = ft_params1(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
dev[0].flush_scan_cache()
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
@ -1115,12 +1115,12 @@ def test_ap_ft_over_ds_pull_vlan(dev, apdev):
params["pmk_r1_push"] = "0"
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd0 = hostapd.add_ap(apdev[0]['ifname'], params)
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params["pmk_r1_push"] = "0"
params['dynamic_vlan'] = "1"
params['accept_mac_file'] = filename
hapd1 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd1 = hostapd.add_ap(apdev[1], params)
dev[0].flush_scan_cache()
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,

View file

@ -131,7 +131,7 @@ def test_ap_open_assoc_timeout(dev, apdev):
def test_ap_open_auth_drop_sta(dev, apdev):
"""AP dropping station after successful authentication"""
hapd = hostapd.add_ap(apdev[0]['ifname'], {"ssid": "open"})
hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
dev[0].scan(freq="2412")
hapd.set("ext_mgmt_frame_handling", "1")
dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",

View file

@ -3759,6 +3759,21 @@ def test_rsn_eapol_m3_extra(dev, apdev):
dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
def test_rsn_eapol_m3_extra_long(dev, apdev):
"""Long extra KDE in EAPOL-Key msg 3/4"""
ssid = "test-rsn"
passphrase = 'qwertyuiop'
params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
# Add a reserved KDEs into EAPOL-Key msg 3/4
val = 'dd0507c0d19311'
val += 'ddff69b847070102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafb'
val += 'dd085ba59d7911223344'
val += 'dd0a000face4112233445566'
params['eapol_m3_elements'] = val
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
def test_rsn_eapol_m3_no_encrypt(dev, apdev):
"""EAPOL-Key msg 3/4 Key Data field not encrypted"""
ssid = "test-rsn"

View file

@ -800,17 +800,21 @@ def test_ap_vlan_psk(dev, apdev, params):
if vlan_id != i + 1:
raise Exception("Unexpected vlan_id %d for dev[%d]" % (vlan_id, i))
def test_ap_vlan_sae(dev, apdev, params):
"""AP VLAN based on SAE Password Identifier"""
for i in range(3):
check_sae_capab(dev[i])
def start_ap_vlan_sae(apdev):
params = hostapd.wpa2_params(ssid="test-sae-vlan")
params['wpa_key_mgmt'] = 'SAE'
params['sae_password'] = ['pw1|vlanid=1|id=id1',
'pw2|mac=ff:ff:ff:ff:ff:ff|vlanid=2|id=id2',
'pw3|vlanid=3|id=id3']
params['dynamic_vlan'] = "1"
hapd = hostapd.add_ap(apdev[0], params)
params['wpa_group_rekey'] = '10'
return hostapd.add_ap(apdev, params)
def test_ap_vlan_sae(dev, apdev, params):
"""AP VLAN based on SAE Password Identifier"""
for i in range(3):
check_sae_capab(dev[i])
hapd = start_ap_vlan_sae(apdev[0])
for i in range(3):
dev[i].request("SET sae_groups ")
@ -830,3 +834,42 @@ def test_ap_vlan_sae(dev, apdev, params):
vlan_id = int(sta["vlan_id"])
if vlan_id != i + 1:
raise Exception("Unexpected vlan_id %d for dev[%d]" % (vlan_id, i))
ev = dev[i].wait_event(["RSN: Group rekeying completed"], timeout=11)
if ev is None:
raise Exception("GTK rekey timed out")
time.sleep(1)
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
hwsim_utils.test_connectivity_iface(dev[1], hapd, "brvlan2")
hwsim_utils.test_connectivity_iface(dev[2], hapd, "brvlan3")
def test_ap_vlan_sae_group_rekey(dev, apdev, params):
"""AP VLAN and group rekeying"""
check_sae_capab(dev[0])
hapd = start_ap_vlan_sae(apdev[0])
dev[0].set("sae_groups", "")
dev[0].connect("test-sae-vlan", sae_password="pw1",
sae_password_id="id1",
key_mgmt="SAE", scan_freq="2412")
hapd.wait_sta()
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
hapd.set("ext_eapol_frame_io", "1")
ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
if ev is None:
raise Exception("Timeout on EAPOL-TX from hostapd")
time.sleep(0.1)
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
hapd.set("ext_eapol_frame_io", "0")
ev = dev[0].wait_event(["RSN: Group rekeying completed"], timeout=11)
if ev is None:
raise Exception("GTK rekey timed out")
time.sleep(1)
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")

View file

@ -2314,6 +2314,23 @@ def test_dpp_auto_connect_legacy_sae_2(dev, apdev):
finally:
dev[0].set("dpp_config_processing", "0", allow_fail=True)
def test_dpp_auto_connect_legacy_sae_3(dev, apdev):
"""DPP and auto connect (legacy SAE with short password)"""
try:
run_dpp_auto_connect_legacy(dev, apdev, conf='sta-sae', sae_only=True,
password="1234567")
finally:
dev[0].set("dpp_config_processing", "0", allow_fail=True)
def test_dpp_auto_connect_legacy_sae_pw_id(dev, apdev):
"""DPP and auto connect (legacy SAE with password identifier)"""
check_dpp_capab(dev[0], min_ver=3)
try:
run_dpp_auto_connect_legacy(dev, apdev, conf='sta-sae', sae_only=True,
password_id="id")
finally:
dev[0].set("dpp_config_processing", "0", allow_fail=True)
def test_dpp_auto_connect_legacy_psk_sae_1(dev, apdev):
"""DPP and auto connect (legacy PSK+SAE)"""
try:
@ -2339,16 +2356,22 @@ def test_dpp_auto_connect_legacy_psk_sae_3(dev, apdev):
def run_dpp_auto_connect_legacy(dev, apdev, conf='sta-psk',
ssid_charset=None,
psk_sae=False, sae_only=False):
psk_sae=False, sae_only=False,
password="secret passphrase",
password_id=None):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
params = hostapd.wpa2_params(ssid="dpp-legacy",
passphrase="secret passphrase")
if sae_only:
params['wpa_key_mgmt'] = 'SAE'
params['ieee80211w'] = '2'
elif psk_sae:
if sae_only and password_id:
params = hostapd.wpa3_params(ssid="dpp-legacy",
password=password + '|id=' + password_id)
elif sae_only:
params = hostapd.wpa3_params(ssid="dpp-legacy",
password=password)
else:
params = hostapd.wpa2_params(ssid="dpp-legacy",
passphrase=password)
if psk_sae:
params['wpa_key_mgmt'] = 'WPA-PSK SAE'
params['ieee80211w'] = '1'
params['sae_require_mfp'] = '1'
@ -2363,7 +2386,7 @@ def run_dpp_auto_connect_legacy(dev, apdev, conf='sta-psk',
dev[0].dpp_listen(2412)
dev[1].dpp_auth_init(uri=uri0, conf=conf, ssid="dpp-legacy",
ssid_charset=ssid_charset,
passphrase="secret passphrase")
passphrase=password, password_id=password_id)
wait_auth_success(dev[0], dev[1], configurator=dev[1], enrollee=dev[0])
if ssid_charset:
ev = dev[0].wait_event(["DPP-CONFOBJ-SSID-CHARSET"], timeout=1)

View file

@ -13,6 +13,7 @@ from hwsim import HWSimRadio
import hwsim_utils
from wpasupplicant import WpaSupplicant
import re
import mld
from tshark import run_tshark
from test_gas import hs20_ap_params
from test_dpp import check_dpp_capab, wait_auth_success
@ -104,8 +105,9 @@ def eht_verify_status(wpas, hapd, freq, bw, is_ht=False, is_vht=False,
time.sleep(0.1)
_eht_verify_links(wpas, valid_links, active_links)
def traffic_test(wpas, hapd, success=True):
hwsim_utils.test_connectivity(wpas, hapd, success_expected=success)
def traffic_test(wpas, hapd, success=True, ifname2=None):
hwsim_utils.test_connectivity(wpas, hapd, success_expected=success,
ifname2=ifname2)
def test_eht_open(dev, apdev):
"""EHT AP with open mode configuration"""
@ -238,8 +240,8 @@ def test_eht_sae_mlo_tm(dev, apdev):
dev[0].set("sae_pwe", "0")
dev[1].set("sae_groups", "")
def eht_mld_enable_ap(iface, params):
hapd = hostapd.add_mld_link(iface, params)
def eht_mld_enable_ap(iface, link_id, params):
hapd = hostapd.add_mld_link(iface, link_id, params)
hapd.enable()
ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=1)
@ -251,7 +253,7 @@ def eht_mld_enable_ap(iface, params):
return hapd
def eht_mld_ap_wpa2_params(ssid, passphrase=None, key_mgmt="WPA-PSK-SHA256",
mfp="2", pwe=None, beacon_prot="1"):
mfp="2", pwe=None, beacon_prot="1", bridge=False):
params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase,
wpa_key_mgmt=key_mgmt, ieee80211w=mfp)
params['ieee80211n'] = '1'
@ -261,6 +263,8 @@ def eht_mld_ap_wpa2_params(ssid, passphrase=None, key_mgmt="WPA-PSK-SHA256",
params['hw_mode'] = 'g'
params['group_mgmt_cipher'] = "AES-128-CMAC"
params['beacon_prot'] = beacon_prot
if bridge:
params['bridge'] = 'ap-br0'
if pwe is not None:
params['sae_pwe'] = pwe
@ -307,8 +311,8 @@ def test_eht_mld_discovery(dev, apdev):
"hw_mode": "g",
"channel": "2"}
hapd0 = eht_mld_enable_ap(hapd_iface, link0_params)
hapd1 = eht_mld_enable_ap(hapd_iface, link1_params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link0_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link1_params)
# Only scan link 0
res = wpas.request("SCAN freq=2412")
@ -388,13 +392,13 @@ def _eht_mld_owe_two_links(dev, apdev, second_link_disabled=False,
ssid = "mld_ap_owe_two_link"
params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2")
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
if second_link_disabled:
params['mld_indicate_disabled'] = '1'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
# Check legacy client connection
dev[0].connect(ssid, scan_freq="2437", key_mgmt="OWE", ieee80211w="2")
@ -446,7 +450,7 @@ def test_eht_mld_sae_single_link(dev, apdev):
params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE",
mfp="2", pwe='2')
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
wpas.set("sae_pwe", "1")
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412",
@ -458,7 +462,7 @@ def test_eht_mld_sae_single_link(dev, apdev):
traffic_test(wpas, hapd0)
def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1",
disable_enable=False):
disable_enable=False, bridge=False):
with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \
HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface):
@ -469,13 +473,18 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1",
ssid = "mld_ap_sae_two_link"
params = eht_mld_ap_wpa2_params(ssid, passphrase,
key_mgmt="SAE", mfp="2", pwe='1',
beacon_prot=beacon_prot)
beacon_prot=beacon_prot,
bridge=bridge)
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
if bridge:
hapd0.cmd_execute(['brctl', 'setfd', 'ap-br0', '0'])
hapd0.cmd_execute(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
wpas.set("sae_pwe", "1")
@ -494,8 +503,8 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1",
if wpas.get_status_field('sae_group') != '19':
raise Exception("Expected SAE group not used")
traffic_test(wpas, hapd0)
traffic_test(wpas, hapd1)
traffic_test(wpas, hapd0, ifname2='ap-br0' if bridge else None)
traffic_test(wpas, hapd1, ifname2='ap-br0' if bridge else None)
if disable_enable:
if "OK" not in hapd0.request("DISABLE_MLD"):
@ -534,8 +543,8 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1",
wpas.wait_connected()
hapd0.wait_sta()
hapd1.wait_sta()
traffic_test(wpas, hapd0)
traffic_test(wpas, hapd1)
traffic_test(wpas, hapd0, ifname2='ap-br0' if bridge else None)
traffic_test(wpas, hapd1, ifname2='ap-br0' if bridge else None)
def test_eht_mld_sae_two_links(dev, apdev):
"""EHT MLD AP with MLD client SAE H2E connection using two links"""
@ -549,6 +558,10 @@ def test_eht_mld_sae_two_links_disable_enable(dev, apdev):
"""AP MLD with two links and disabling/enabling full AP MLD"""
run_eht_mld_sae_two_links(dev, apdev, disable_enable=True)
def test_eht_mld_sae_two_links_bridge(dev, apdev):
"""AP MLD with two links in a bridge"""
run_eht_mld_sae_two_links(dev, apdev, bridge=True)
def test_eht_mld_sae_ext_one_link(dev, apdev):
"""EHT MLD AP with MLD client SAE-EXT H2E connection using single link"""
with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \
@ -561,7 +574,7 @@ def test_eht_mld_sae_ext_one_link(dev, apdev):
ssid = "mld_ap_sae_ext_single_link"
params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY")
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412",
key_mgmt="SAE-EXT-KEY", ieee80211w="2")
@ -584,11 +597,11 @@ def test_eht_mld_sae_ext_two_links(dev, apdev):
params = eht_mld_ap_wpa2_params(ssid, passphrase,
key_mgmt="SAE-EXT-KEY")
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
key_mgmt="SAE-EXT-KEY", ieee80211w="2")
@ -607,11 +620,11 @@ def test_eht_mld_sae_legacy_client(dev, apdev):
params = eht_mld_ap_wpa2_params(ssid, passphrase,
key_mgmt="SAE", mfp="2", pwe='1')
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
try:
dev[0].set("sae_groups", "")
@ -647,11 +660,11 @@ def test_eht_mld_sae_transition(dev, apdev):
key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256",
mfp="1")
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
key_mgmt="SAE-EXT-KEY", ieee80211w="2")
@ -683,11 +696,11 @@ def test_eht_mld_ptk_rekey(dev, apdev):
mfp="1")
params['wpa_ptk_rekey'] = '5'
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
key_mgmt="SAE-EXT-KEY", ieee80211w="2")
@ -723,11 +736,11 @@ def test_eht_mld_gtk_rekey(dev, apdev):
mfp="1")
params['wpa_group_rekey'] = '5'
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
key_mgmt="SAE-EXT-KEY", ieee80211w="2")
@ -745,10 +758,9 @@ def test_eht_mld_gtk_rekey(dev, apdev):
if "CTRL-EVENT-DISCONNECTED" in ev:
raise Exception("Disconnect instead of rekey")
#TODO: Uncomment these ones GTK rekeying works for MLO
#time.sleep(0.1)
#traffic_test(wpas, hapd0)
#traffic_test(wpas, hapd1)
time.sleep(0.1)
traffic_test(wpas, hapd0)
traffic_test(wpas, hapd1)
def test_eht_ml_probe_req(dev, apdev):
"""AP MLD with two links and non-AP MLD sending ML Probe Request"""
@ -763,11 +775,11 @@ def test_eht_ml_probe_req(dev, apdev):
params = eht_mld_ap_wpa2_params(ssid, passphrase,
key_mgmt="SAE-EXT-KEY")
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
bssid = hapd0.own_addr()
wpas.scan_for_bss(bssid, freq=2412)
@ -804,11 +816,11 @@ def test_eht_mld_connect_probes(dev, apdev, params):
key_mgmt="SAE", pwe='2')
link_params['channel'] = '1'
link_params['bssid'] = '00:11:22:33:44:01'
hapd0 = eht_mld_enable_ap(hapd_iface, link_params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link_params)
link_params['channel'] = '6'
link_params['bssid'] = '00:11:22:33:44:02'
hapd1 = eht_mld_enable_ap(hapd_iface, link_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link_params)
wpas.set("sae_pwe", "1")
wpas.connect(ssid, sae_password= passphrase, ieee80211w="2",
@ -849,11 +861,11 @@ def test_eht_tx_link_rejected_connect_other(dev, apdev, params):
key_mgmt="SAE", pwe='2')
link_params['channel'] = '1'
link_params['bssid'] = '00:11:22:33:44:01'
hapd0 = eht_mld_enable_ap(hapd_iface, link_params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link_params)
link_params['channel'] = '6'
link_params['bssid'] = '00:11:22:33:44:02'
hapd1 = eht_mld_enable_ap(hapd_iface, link_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link_params)
wpas.set("sae_pwe", "1")
with fail_test(hapd0, 1, "hostapd_get_aid"):
@ -879,11 +891,11 @@ def test_eht_all_links_rejected(dev, apdev, params):
key_mgmt="SAE", pwe='2')
link_params['channel'] = '1'
link_params['bssid'] = '00:11:22:33:44:01'
hapd0 = eht_mld_enable_ap(hapd_iface, link_params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link_params)
link_params['channel'] = '6'
link_params['bssid'] = '00:11:22:33:44:02'
hapd1 = eht_mld_enable_ap(hapd_iface, link_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link_params)
wpas.set("mld_connect_bssid_pref", "00:11:22:33:44:01")
wpas.set("sae_pwe", "1")
@ -922,11 +934,11 @@ def test_eht_connect_invalid_link(dev, apdev, params):
key_mgmt="SAE", pwe='2')
link_params['channel'] = '1'
link_params['bssid'] = '00:11:22:33:44:01'
hapd0 = eht_mld_enable_ap(hapd_iface, link_params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link_params)
link_params['channel'] = '6'
link_params['bssid'] = '00:11:22:33:44:02'
hapd1 = eht_mld_enable_ap(hapd_iface, link_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link_params)
# We scan for both APs, then try to connect to link 0, but only the
# second attempt will work if mac80211 rejects the second link.
@ -957,10 +969,10 @@ def test_eht_mld_link_removal(dev, apdev):
ssid = "mld_ap_owe_two_link"
params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2")
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE",
ieee80211w="2")
@ -1010,11 +1022,11 @@ def test_eht_mld_bss_trans_mgmt_link_removal_imminent(dev, apdev):
params["bss_transition"] = "1"
params["mbo"] = "1"
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE",
ieee80211w="2")
@ -1062,11 +1074,11 @@ def test_eht_ap_mld_proto(dev, apdev):
ssid = "mld_ap_owe_two_link"
params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2")
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
ap_mld_addr = hapd0.get_status_field("mld_addr[0]").replace(':', '')
bssid0 = hapd0.own_addr().replace(':', '')
@ -1351,6 +1363,7 @@ def _test_eht_6ghz(dev, apdev, channel, op_class, ccfs1):
raise Exception("STATUS did not indicate ieee80211be=1")
dev[0].set("sae_pwe", "1")
dev[0].set("sae_groups", "")
freq = 5950 + channel * 5
bw = _6ghz_op_class_to_bw(op_class)
@ -1449,11 +1462,11 @@ def test_eht_mld_gas(dev, apdev):
params['venue_group'] = "7"
params['venue_type'] = "1"
params['venue_name'] = "eng:Example venue"
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
bssid0 = hapd0.own_addr()
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
bssid1 = hapd1.own_addr()
wpas.scan_for_bss(bssid0, freq="2412")
@ -1485,10 +1498,10 @@ def test_eht_mld_dpp_responder_while_assoc(dev, apdev):
ssid = "owe_two_link"
params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2")
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE",
ieee80211w="2")
@ -1513,10 +1526,10 @@ def _eht_mld_disconnect(dev, apdev, disassoc=True):
ssid = "mld_ap_owe_two_link"
params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2")
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd0_iface, params)
hapd1 = eht_mld_enable_ap(hapd0_iface, 1, params)
wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE",
ieee80211w="2")
@ -1571,7 +1584,7 @@ def test_eht_mld_non_pref_chan(dev, apdev):
params["bss_transition"] = "1"
params["mbo"] = "1"
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
if "OK" not in wpas.request("SET non_pref_chan 81:7:200:1 81:9:100:2"):
raise Exception("Failed to set non-preferred channel list")
@ -1659,7 +1672,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev):
params["mbo"] = "1"
params["rrm_beacon_report"] = "1"
hapd0 = eht_mld_enable_ap(hapd0_iface, params)
hapd0 = eht_mld_enable_ap(hapd0_iface, 0, params)
wpas.connect(ssid, scan_freq="2412", key_mgmt="OWE", ieee80211w="2",
owe_only="1")
@ -1673,7 +1686,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev):
other_ssid = "other"
params = eht_mld_ap_wpa2_params(other_ssid, key_mgmt="OWE", mfp="2")
params["channel"] = '6'
hapd1 = eht_mld_enable_ap(hapd1_iface, params)
hapd1 = eht_mld_enable_ap(hapd1_iface, 0, params)
# Issue a beacon request for the second AP
addr = wpas.own_addr()
@ -1712,7 +1725,7 @@ def test_eht_mld_legacy_stas(dev, apdev):
mfp="2", pwe='2')
params['rsn_pairwise'] = "CCMP GCMP-256"
params['sae_groups'] = "19 20"
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
for i in range(3):
dev[i].set("sae_groups", "")
@ -1751,7 +1764,7 @@ def test_eht_mld_and_mlds(dev, apdev):
mfp="2", pwe='2')
params['rsn_pairwise'] = "CCMP GCMP-256"
params['sae_groups'] = "19 20"
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
wpas.set("sae_pwe", "1")
wpas.connect(ssid, sae_password=password, scan_freq="2412",
@ -1816,10 +1829,10 @@ def test_eht_mlo_csa(dev, apdev):
params = eht_mld_ap_wpa2_params(ssid, passphrase,
key_mgmt="SAE", mfp="2", pwe='1')
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
wpas.set("sae_pwe", "1")
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
@ -1837,6 +1850,21 @@ def test_eht_mlo_csa(dev, apdev):
logger.info("Test traffic after 1st link CSA completes")
traffic_test(wpas, hapd0)
logger.info("Perform CSA on 2nd link")
mlo_perform_csa(hapd1, "CHAN_SWITCH 5 2412 ht he eht blocktx",
2412, wpas)
logger.info("Test traffic after 2nd link CSA completes")
traffic_test(wpas, hapd1)
logger.info("Perform CSA on 2nd link and bring it back to original channel")
mlo_perform_csa(hapd1, "CHAN_SWITCH 5 2437 ht he eht blocktx",
2437, wpas)
logger.info("Test traffic again after 2nd link CSA completes")
traffic_test(wpas, hapd1)
logger.info("Perform CSA on 1st link and bring it back to original channel")
mlo_perform_csa(hapd0, "CHAN_SWITCH 5 2412 ht he eht blocktx",
2412, wpas)
@ -1844,8 +1872,6 @@ def test_eht_mlo_csa(dev, apdev):
logger.info("Test traffic again after 1st link CSA completes")
traffic_test(wpas, hapd0)
#TODO: CSA on non-first link
def create_base_conf_file(iface, channel, prefix='hostapd-', hw_mode='g',
op_class=None):
# Create configuration file and add phy characteristics
@ -1903,7 +1929,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex,
params['sae_pwe'] = "2"
params['group_mgmt_cipher'] = "AES-128-CMAC"
params['beacon_prot'] = "1"
params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel)
params["ctrl_interface"] = "/var/run/hostapd/"
params["bssid"] = bssid_regex % (i + 1)
if rnr:
@ -1911,7 +1937,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex,
append_bss_conf_to_file(f, ifname, params, first=(i == 0))
hapds.append([ifname, params["ctrl_interface"], i])
hapds.append([ifname, i])
f.close()
@ -1956,15 +1982,15 @@ def get_mld_devs(hapd_iface, count, prefix, rnr=False):
start_ap(prefix, fname1 + " " + fname2)
hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1],
bssidx=hapds1[0][2])
hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1],
bssidx=hapds2[0][2])
hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], bssidx=hapds1[0][1],
link=0)
hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], bssidx=hapds2[0][1],
link=1)
hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1],
bssidx=hapds1[1][2])
hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1],
bssidx=hapds2[1][2])
hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], bssidx=hapds1[1][1],
link=0)
hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], bssidx=hapds2[1][1],
link=1)
if not hapd_mld1_link0.ping():
raise Exception("Could not ping hostapd")
@ -2144,12 +2170,12 @@ def test_eht_mlo_color_change(dev, apdev):
key_mgmt="SAE", mfp="2", pwe='1')
params['he_bss_color'] = '42'
hapd0 = eht_mld_enable_ap(hapd_iface, params)
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params['channel'] = '6'
params['he_bss_color'] = '24'
hapd1 = eht_mld_enable_ap(hapd_iface, params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
logger.info("Perform CCA on 1st link")
if "OK" not in hapd0.request("COLOR_CHANGE 10"):
@ -2190,3 +2216,36 @@ def test_eht_mlo_color_change(dev, apdev):
hapd0.dump_monitor()
hapd1.dump_monitor()
def test_eht_mld_control_socket_connectivity(dev, apdev):
"""AP MLD control socket connectivity"""
with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \
HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface):
ssid = "mld_ap"
link0_params = {"ssid": ssid,
"hw_mode": "g",
"channel": "1"}
link1_params = {"ssid": ssid,
"hw_mode": "g",
"channel": "2"}
hapd0 = eht_mld_enable_ap(hapd_iface, 0, link0_params)
hapd1 = eht_mld_enable_ap(hapd_iface, 1, link1_params)
mld_dev = mld.get_mld_obj(hapd_iface)
# Check status of each link
res = str(mld_dev.request("LINKID 0 STATUS"))
logger.info("LINK 0 STATUS:\n" + res)
if "state" not in res:
raise Exception("Failed to get link 0 status via MLD socket")
if 'link_id=0' not in res.splitlines():
raise Exception("link_id=0 not reported for link 0")
res = mld_dev.request("LINKID 1 STATUS")
logger.info("LINK 1 STATUS:\n" + res)
if "state" not in res:
raise Exception("Failed to get link 1 status via MLD socket")
if 'link_id=1' not in res.splitlines():
raise Exception("link_id=0 not reported for link 1")

View file

@ -36,7 +36,7 @@ def test_fils_sk_full_auth(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['wpa_group_rekey'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].flush_scan_cache()
dev[0].scan_for_bss(bssid, freq=2412)
@ -86,7 +86,7 @@ def test_fils_sk_sha384_full_auth(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['wpa_group_rekey'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].flush_scan_cache()
dev[0].scan_for_bss(bssid, freq=2412)
@ -134,7 +134,7 @@ def test_fils_sk_pmksa_caching(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -202,7 +202,7 @@ def test_fils_sk_pmksa_caching_ocv(dev, apdev, params):
params['ieee80211w'] = '1'
params['ocv'] = '1'
try:
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
except Exception as e:
if "Failed to set hostapd parameter ocv" in str(e):
raise HwsimSkip("OCV not supported")
@ -279,7 +279,7 @@ def test_fils_sk_pmksa_caching_and_cache_id(dev, apdev):
params["eap_fast_a_id_info"] = "test server"
params["eap_server_erp"] = "1"
params["erp_domain"] = "example.com"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -305,7 +305,7 @@ def test_fils_sk_pmksa_caching_and_cache_id(dev, apdev):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['fils_cache_id'] = "abcd"
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(bssid2, freq=2412)
@ -348,7 +348,7 @@ def test_fils_sk_pmksa_caching_ctrl_ext(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['fils_cache_id'] = "ffee"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -386,7 +386,7 @@ def test_fils_sk_pmksa_caching_ctrl_ext(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['fils_cache_id'] = "ffee"
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(bssid2, freq=2412)
dev[0].set_network(id, "bssid", bssid2)
@ -417,7 +417,7 @@ def run_fils_sk_erp(dev, apdev, key_mgmt, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -458,7 +458,7 @@ def test_fils_sk_erp_followed_by_pmksa_caching(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -533,7 +533,7 @@ def test_fils_sk_erp_another_ssid(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -557,7 +557,7 @@ def test_fils_sk_erp_another_ssid(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].dump_monitor()
@ -600,7 +600,7 @@ def test_fils_sk_multiple_realms(dev, apdev, params):
params['fils_realm'] = fils_realms
params['fils_cache_id'] = "1234"
params['hessid'] = bssid
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].flush_scan_cache()
dev[0].scan_for_bss(bssid, freq=2412)
@ -785,7 +785,7 @@ def run_fils_sk_hlp(dev, apdev, rapid_commit_server, params):
params['fils_hlp_wait_time'] = '10000'
if not rapid_commit_server:
params['dhcp_rapid_commit_proxy'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -890,7 +890,7 @@ def test_fils_sk_hlp_timeout(dev, apdev, params):
bssid = apdev[0]['bssid']
params = fils_hlp_config(fils_hlp_wait_time=30)
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -937,7 +937,7 @@ def test_fils_sk_hlp_oom(dev, apdev, params):
bssid = apdev[0]['bssid']
params = fils_hlp_config(fils_hlp_wait_time=500)
params['dhcp_rapid_commit_proxy'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1037,7 +1037,7 @@ def test_fils_sk_hlp_req_parsing(dev, apdev, params):
bssid = apdev[0]['bssid']
params = fils_hlp_config(fils_hlp_wait_time=30)
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1212,7 +1212,7 @@ def test_fils_sk_hlp_dhcp_parsing(dev, apdev, params):
bssid = apdev[0]['bssid']
params = fils_hlp_config(fils_hlp_wait_time=30)
params['dhcp_rapid_commit_proxy'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1374,7 +1374,7 @@ def test_fils_sk_erp_and_reauth(dev, apdev, params):
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
params['broadcast_deauth'] = '0'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1413,7 +1413,7 @@ def test_fils_sk_erp_sim(dev, apdev, params):
params['auth_server_port'] = "18128"
params['fils_realm'] = realm
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1499,7 +1499,7 @@ def run_fils_sk_pfs(dev, apdev, group, params):
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
params['fils_dh_group'] = group
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1542,7 +1542,7 @@ def test_fils_sk_pfs_group_mismatch(dev, apdev, params):
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
params['fils_dh_group'] = "20"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1577,7 +1577,7 @@ def test_fils_sk_pfs_pmksa_caching(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['fils_dh_group'] = "19"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1694,7 +1694,7 @@ def test_fils_sk_auth_mismatch(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1741,7 +1741,7 @@ def setup_fils_rekey(dev, apdev, params, wpa_ptk_rekey=0, wpa_group_rekey=0,
params['disable_pmksa_caching'] = '1'
if ext_key_id:
params['extended_key_id'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1823,7 +1823,7 @@ def test_fils_and_ft(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -1856,7 +1856,7 @@ def test_fils_and_ft(dev, apdev, params):
params['r0kh'] = ["02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f"]
params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f"
params['ieee80211w'] = "1"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].dump_monitor()
@ -1893,7 +1893,7 @@ def test_fils_and_ft(dev, apdev, params):
params['r1_key_holder'] = "000102030406"
params['r0kh'] = ["02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f"]
params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f"
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(apdev[1]['bssid'], freq="2412", force_scan=True)
# FIX: Cannot use FT-over-DS without the FTE MIC issue addressed
@ -1984,7 +1984,7 @@ def run_fils_and_ft_setup(dev, apdev, params, key_mgmt):
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
params['ieee80211w'] = "2"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2021,7 +2021,7 @@ def run_fils_and_ft_setup(dev, apdev, params, key_mgmt):
"02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f"]
params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f"
params['ieee80211w'] = "2"
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].dump_monitor()
@ -2052,7 +2052,7 @@ def run_fils_and_ft_setup(dev, apdev, params, key_mgmt):
params['r0kh'] = ["02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f",
"02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"]
params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f"
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
return hapd, hapd2
@ -2070,7 +2070,7 @@ def test_fils_assoc_replay(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2163,7 +2163,7 @@ def test_fils_sk_erp_server_flush(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2260,7 +2260,7 @@ def run_fils_sk_erp_radius_ext(dev, apdev, params):
params['erp_domain'] = 'erp.example.com'
params['fils_realm'] = 'erp.example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2313,7 +2313,7 @@ def run_fils_sk_erp_radius_roam(dev, apdev):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2329,7 +2329,7 @@ def run_fils_sk_erp_radius_roam(dev, apdev):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(bssid2, freq=2412)
@ -2362,7 +2362,7 @@ def test_fils_sk_erp_roam_diff_akm(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2389,7 +2389,7 @@ def test_fils_sk_erp_roam_diff_akm(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
dev[0].scan_for_bss(bssid2, freq=2412)
@ -2452,7 +2452,7 @@ def test_fils_discovery_frame(dev, apdev, params):
params['wpa_group_rekey'] = '1'
params['fils_discovery_min_interval'] = '20'
params['fils_discovery_max_interval'] = '20'
hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
if "OK" not in hapd.request("ENABLE"):
raise HwsimSkip("FILS Discovery frame transmission not supported")
@ -2493,7 +2493,7 @@ def run_fils_offload_to_driver(dev, apdev, params):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev.request("ERP_FLUSH")
id = dev.connect("fils", key_mgmt="FILS-SHA256",
@ -2535,7 +2535,7 @@ def test_fils_sk_okc(dev, apdev, params):
params['auth_server_port'] = "18128"
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].request("ERP_FLUSH")
@ -2584,7 +2584,7 @@ def test_fils_sk_ptk_rekey_request(dev, apdev, params):
params['erp_send_reauth_start'] = '1'
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].flush_scan_cache()
dev[0].scan_for_bss(bssid, freq=2412)

View file

@ -0,0 +1,16 @@
# hostapd error paths
# Copyright (c) 2024, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import hostapd
from utils import *
def test_hostapd_error_drv_init(dev, apdev):
"""hostapd error path on driver interface initialization failure"""
hapd = hostapd.add_ap(apdev[0], {"ssid": "ctrl"})
with fail_test(hapd, 1, "nl80211_setup_ap"):
hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open"}, no_enable=True)
if "FAIL" not in hapd1.request("ENABLE"):
raise Exception("ENABLE succeeded unexpectedly")

View file

@ -428,8 +428,11 @@ def _test_wifi_display_parsing(dev):
dev[1].p2p_connect_group(dev[0].p2p_dev_addr(), pin, timeout=60,
social=True, freq=2412)
bssid = dev[0].get_group_status_field('bssid')
dev[2].flush_scan_cache()
dev[2].scan_for_bss(bssid, freq=2412, force_scan=True)
bss = dev[2].get_bss(bssid)
if 'wfd_subelems' not in bss:
raise Exception("Missing WFD elements in scan results")
if bss['wfd_subelems'] != "000006" + wfd_devinfo:
raise Exception("Unexpected WFD elements in scan results: " + bss['wfd_subelems'])

View file

@ -569,7 +569,7 @@ def pasn_fils_setup(wpas, apdev, params, key_mgmt):
params['erp_domain'] = 'example.com'
params['fils_realm'] = 'example.com'
params['disable_pmksa_caching'] = '1'
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
id = wpas.connect("fils", key_mgmt=key_mgmt,
eap="PSK", identity="psk.user@example.com",

View file

@ -64,9 +64,9 @@ def check_nr_results(dev, bssids=None, lci=False, civic=False):
def test_rrm_neighbor_db(dev, apdev):
"""hostapd ctrl_iface SET_NEIGHBOR"""
params = {"ssid": "test", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
params = {"ssid": "test2", "rrm_neighbor_report": "1"}
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
res = hapd.request("SHOW_NEIGHBOR")
if len(res.splitlines()) != 1:
@ -215,7 +215,7 @@ def test_rrm_neighbor_db(dev, apdev):
def test_rrm_neighbor_db_failures(dev, apdev):
"""hostapd ctrl_iface SET_NEIGHBOR failures"""
params = {"ssid": "test", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
cmd = "SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic
tests = [(1, "hostapd_neighbor_add"),
(1, "wpabuf_dup;hostapd_neighbor_set"),
@ -229,7 +229,7 @@ def test_rrm_neighbor_db_failures(dev, apdev):
def test_rrm_neighbor_db_disabled(dev, apdev):
"""hostapd ctrl_iface SHOW_NEIGHBOR while neighbor report disabled"""
params = {"ssid": "test"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
if "FAIL" not in hapd.request("SHOW_NEIGHBOR"):
raise Exception("SHOW_NEIGHBOR accepted")
@ -242,9 +242,9 @@ def test_rrm_neighbor_rep_req(dev, apdev):
nr3 = "dd112233445500000000510107"
params = {"ssid": "test", "rnr": "1"}
hostapd.add_ap(apdev[0]['ifname'], params)
hostapd.add_ap(apdev[0], params)
params = {"ssid": "test2", "rrm_neighbor_report": "1", "rnr": "1"}
hapd = hostapd.add_ap(apdev[1]['ifname'], params)
hapd = hostapd.add_ap(apdev[1], params)
bssid1 = apdev[1]['bssid']
@ -351,7 +351,7 @@ def test_rrm_neighbor_rep_oom(dev, apdev):
nr3 = "dd112233445500000000510107"
params = {"ssid": "test", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
@ -367,7 +367,7 @@ def test_rrm_lci_req(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
# station not specified
if "FAIL" not in hapd.request("REQ_LCI "):
@ -400,7 +400,7 @@ def test_rrm_lci_req_timeout(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].request("SET LCI " + lci)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -431,7 +431,7 @@ def test_rrm_lci_req_oom(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].request("SET LCI " + lci)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -454,7 +454,7 @@ def test_rrm_lci_req_ap_oom(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].request("SET LCI " + lci)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -472,7 +472,7 @@ def test_rrm_lci_req_get_reltime_failure(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].request("SET LCI " + lci)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -488,7 +488,7 @@ def test_rrm_neighbor_rep_req_from_conf(dev, apdev):
params = {"ssid": "test2", "rrm_neighbor_report": "1",
"stationary_ap": "1", "lci": lci, "civic": civic}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = apdev[0]['bssid']
@ -504,7 +504,7 @@ def test_rrm_neighbor_rep_req_timeout(dev, apdev):
params = {"ssid": "test2", "rrm_neighbor_report": "1",
"stationary_ap": "1", "lci": lci, "civic": civic}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
@ -523,7 +523,7 @@ def test_rrm_neighbor_rep_req_oom(dev, apdev):
params = {"ssid": "test2", "rrm_neighbor_report": "1",
"stationary_ap": "1", "lci": lci, "civic": civic}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
@ -548,7 +548,7 @@ def test_rrm_neighbor_rep_req_disconnect(dev, apdev):
params = {"ssid": "test2", "rrm_neighbor_report": "1",
"stationary_ap": "1", "lci": lci, "civic": civic}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
if "FAIL" not in dev[0].request("NEIGHBOR_REP_REQUEST"):
raise Exception("Request accepted while disconnected")
@ -570,7 +570,7 @@ def test_rrm_neighbor_rep_req_not_supported(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "test2", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
@ -583,7 +583,7 @@ def test_rrm_neighbor_rep_req_busy(dev, apdev):
params = {"ssid": "test2", "rrm_neighbor_report": "1",
"stationary_ap": "1", "lci": lci, "civic": civic}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test2", key_mgmt="NONE", scan_freq="2412")
@ -608,7 +608,7 @@ def test_rrm_ftm_range_req(dev, apdev):
def run_rrm_ftm_range_req(dev, apdev):
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
# station not specified
@ -694,7 +694,7 @@ def test_rrm_ftm_range_req_timeout(dev, apdev):
def run_rrm_ftm_range_req_timeout(dev, apdev):
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
# Override RM capabilities to include FTM range report
@ -734,7 +734,7 @@ def test_rrm_ftm_range_req_failure(dev, apdev):
def run_rrm_ftm_range_req_failure(dev, apdev):
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
# Override RM capabilities to include FTM range report
@ -764,7 +764,7 @@ def _test_rrm_ftm_capa_indication(dev, apdev):
params = {"ssid": "ftm",
"ftm_responder": "1",
"ftm_initiator": "1",}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
if "OK" not in dev[0].request("SET ftm_initiator 1"):
raise Exception("could not set ftm_initiator")
@ -1564,7 +1564,7 @@ def test_rrm_beacon_req_active_many(dev, apdev):
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
params['vendor_elements'] = "dd50" + 80*'aa'
hapd = hostapd.add_ap(apdev[1]['ifname'], params)
hapd = hostapd.add_ap(apdev[1], params)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
addr = dev[0].own_addr()
@ -2058,7 +2058,7 @@ def test_rrm_beacon_req_ap_errors(dev, apdev):
def run_rrm_beacon_req_ap_errors(dev, apdev):
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2106,7 +2106,7 @@ def run_rrm_beacon_req_ap_errors(dev, apdev):
def test_rrm_req_reject_oom(dev, apdev):
"""Radio measurement request - OOM while rejecting a request"""
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2129,7 +2129,7 @@ def test_rrm_req_reject_oom(dev, apdev):
def test_rrm_req_when_rrm_not_used(dev, apdev):
"""Radio/link measurement request for non-RRM association"""
params = {"ssid": "rrm"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2268,7 +2268,7 @@ def test_rrm_link_measurement(dev, apdev):
"""Radio measurement request - link measurement"""
check_tx_power_support(dev[0])
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2289,7 +2289,7 @@ def test_rrm_link_measurement_oom(dev, apdev):
"""Radio measurement request - link measurement OOM"""
check_tx_power_support(dev[0])
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2319,7 +2319,7 @@ def test_rrm_rep_parse_proto(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].request("SET LCI " + lci)
@ -2354,7 +2354,7 @@ def test_rrm_unexpected(dev, apdev):
check_rrm_support(dev[0])
params = {"ssid": "rrm", "rrm_neighbor_report": "0"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
dev[0].connect("rrm", key_mgmt="NONE", scan_freq="2412")
@ -2381,7 +2381,7 @@ def check_beacon_req(hapd, addr, idx):
def test_rrm_reassociation(dev, apdev):
"""Radio measurement request - reassociation"""
params = {"ssid": "rrm", "rrm_beacon_report": "1"}
hapd = hostapd.add_ap(apdev[0]['ifname'], params)
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
addr = dev[0].own_addr()
@ -2395,7 +2395,7 @@ def test_rrm_reassociation(dev, apdev):
hapd.wait_sta()
check_beacon_req(hapd, addr, 1)
hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
hapd2 = hostapd.add_ap(apdev[1], params)
bssid2 = hapd2.own_addr()
dev[0].scan_for_bss(bssid2, freq=2412, force_scan=True)
dev[0].roam(bssid2)

View file

@ -0,0 +1,437 @@
# Test cases for RSNE/RSNXE overriding
# Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc.
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
import hostapd
from utils import *
from hwsim import HWSimRadio
from wpasupplicant import WpaSupplicant
from test_eht import eht_mld_enable_ap, eht_verify_status, eht_verify_wifi_version, traffic_test
def test_rsn_override(dev, apdev):
"""RSNE=WPA2-Personal/PMF-optional override=WPA3-Personal/PMF-required (with MLO parameters)"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
bss = dev[0].get_bss(bssid)
flags = bss['flags']
if "PSK" in flags:
raise Exception("Unexpected BSS flags: " + flags)
if "-SAE+SAE-EXT-KEY-" not in flags:
raise Exception("Unexpected BSS flags: " + flags)
if "-GCMP-256+CCMP" not in flags:
raise Exception("Unexpected BSS flags: " + flags)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678", key_mgmt="SAE",
ieee80211w="2", scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override2(dev, apdev):
"""RSNE=WPA2-Personal/PMF-disabled override=WPA3-Personal/PMF-required (with MLO parameters)"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='0')
params['rsn_override_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
bss = dev[0].get_bss(bssid)
flags = bss['flags']
if "PSK" in flags:
raise Exception("Unexpected BSS flags: " + flags)
if "-SAE+SAE-EXT-KEY-" not in flags:
raise Exception("Unexpected BSS flags: " + flags)
if "-GCMP-256+CCMP" not in flags:
raise Exception("Unexpected BSS flags: " + flags)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678", key_mgmt="SAE",
ieee80211w="2", scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override_no_pairwise(dev, apdev):
"""RSN overriding and no pairwise cipher match in RSNEO"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].set("sae_groups", "")
dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK SAE",
pairwise="CCMP", ieee80211w="1", scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override_mld(dev, apdev):
"""AP MLD and RSNE=WPA2-Personal/PMF-disabled override=WPA3-Personal/PMF-required"""
run_rsn_override_mld(dev, apdev, False)
def test_rsn_override_mld_mixed(dev, apdev):
"""AP MLD and RSNE=WPA2-Personal/PMF-disabled override=WPA3-Personal/PMF-required on one link"""
run_rsn_override_mld(dev, apdev, True)
def test_rsn_override_mld_only_sta(dev, apdev):
"""AP MLD and RSN overriding only on STA"""
run_rsn_override_mld(dev, apdev, False, only_sta=True)
def test_rsn_override_mld_too_long_elems(dev, apdev):
"""AP MLD and RSN overriding with too long elements"""
run_rsn_override_mld(dev, apdev, False, too_long_elems=True)
def run_rsn_override_mld(dev, apdev, mixed, only_sta=False,
too_long_elems=False):
with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \
HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface):
wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
wpas.interface_add(wpas_iface)
passphrase = 'qwertyuiop'
ssid = "AP MLD RSN override"
params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
params['ieee80211n'] = '1'
params['ieee80211ax'] = '1'
params['ieee80211be'] = '1'
params['channel'] = '1'
params['hw_mode'] = 'g'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
if only_sta:
params['wpa_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_pairwise'] = 'CCMP GCMP-256'
params['ieee80211w'] = '2'
elif not mixed:
params['rsn_override_key_mgmt'] = 'SAE'
params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP'
params['rsn_override_pairwise_2'] = 'GCMP-256'
params['rsn_override_mfp'] = '1'
params['rsn_override_mfp_2'] = '2'
params1 = dict(params)
if mixed:
params['wpa_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_pairwise'] = 'CCMP GCMP-256'
params['ieee80211w'] = '2'
params['rsn_override_key_mgmt_2'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise_2'] = 'CCMP GCMP-256'
params['rsn_override_mfp_2'] = '2'
params1['rsn_override_key_mgmt_2'] = 'SAE SAE-EXT-KEY'
params1['rsn_override_pairwise_2'] = 'CCMP GCMP-256'
params1['rsn_override_mfp_2'] = '2'
hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
params1['channel'] = '6'
if too_long_elems:
params1['rsnoe_override'] = 'ddff506f9a29' + 251*'cc'
hapd1 = eht_mld_enable_ap(hapd_iface, 1, params1)
wpas.set("sae_pwe", "1")
wpas.set("rsn_overriding", "1")
wpas.connect(ssid, sae_password=passphrase, scan_freq="2412 2437",
key_mgmt="SAE-EXT-KEY", ieee80211w="2", beacon_prot="1",
pairwise="GCMP-256 CCMP", wait_connect=not too_long_elems)
if too_long_elems:
ev = wpas.wait_event(['Associated with'], timeout=10)
if ev is None:
raise Exception("Association not reported")
ev = wpas.wait_event(['EAPOL-RX'], timeout=1)
if ev is None:
raise Exception("EAPOL-Key M1 not reported")
ev = wpas.wait_event(['EAPOL-RX', 'CTRL-EVENT-DISCONNECTED'],
timeout=20)
if ev is None:
raise Exception("Disconnection not reported")
# The AP is expected to fail to send M3 due to RSNOE/RSNO2E/RSNXOE
# being too long to fit into the RSN Override Link KDE.
if 'EAPOL-RX' in ev:
raise Exception("Unexpected EAPOL-Key M3 reported")
return
eht_verify_status(wpas, hapd0, 2412, 20, is_ht=True, mld=True,
valid_links=3, active_links=3)
eht_verify_wifi_version(wpas)
traffic_test(wpas, hapd0)
traffic_test(wpas, hapd1)
if only_sta:
return
dev[0].set("rsn_overriding", "0")
dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK",
scan_freq="2412 2437")
status = wpas.get_status()
logger.debug("wpas STATUS:\n" + str(status))
if status['key_mgmt'] != 'SAE-EXT-KEY' or \
'pmf' not in status or \
status['pmf'] != '2' or \
status['pairwise_cipher'] != 'GCMP-256':
raise Exception("Unexpected result for new STA")
status = dev[0].get_status()
logger.debug("dev[0] STATUS:\n" + str(status))
if status['key_mgmt'] != 'WPA2-PSK' or \
status['pairwise_cipher'] != 'CCMP':
raise Exception("Unexpected result for legacy STA")
def test_rsn_override_connect_cmd(dev, apdev):
"""RSNE=WPA2-Personal/PMF-optional override=WPA3-Personal/PMF-required using cfg80211 connect command"""
wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
wpas.interface_add("wlan5", drv_params="force_connect_cmd=1 rsn_override_in_driver=1")
check_sae_capab(wpas)
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'WPA-PSK-SHA256'
params['rsn_override_pairwise'] = 'CCMP GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
hapd = hostapd.add_ap(apdev[0], params)
wpas.set("rsn_overriding", "1")
wpas.connect(ssid, psk="12345678", key_mgmt="WPA-PSK-SHA256",
ieee80211w="2", scan_freq="2412")
def test_rsn_override_omit_rsnxe(dev, apdev):
"""RSN overriding with RSNXE explicitly omitted"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
params['ssid_protection'] = '1'
params['rsn_override_omit_rsnxe'] = '1'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678", key_mgmt="SAE",
ieee80211w="2", ssid_protection="1",
scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override_replace_ies(dev, apdev):
"""RSN overriding and replaced AP IEs"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'SAE'
params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP'
params['rsn_override_pairwise_2'] = 'GCMP-256'
params['rsn_override_mfp'] = '1'
params['rsn_override_mfp_2'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
params['ssid_protection'] = '1'
params['rsne_override'] = '30180100000fac040100000fac040200000facff000fac020c00'
params['rsnxe_override'] = 'f40320eeee'
params['rsnoe_override'] = 'dd1c506f9a290100000fac040100000fac040200000facff000fac088c00'
params['rsno2e_override'] = 'dd1c506f9a2a0100000fac040100000fac090200000facff000fac18cc00'
params['rsnxoe_override'] = 'dd07506f9a2b20bbbb'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678", key_mgmt="SAE",
ieee80211w="2", ssid_protection="1",
scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override_rsnxe_extensibility(dev, apdev):
"""RSN overriding and RSNXE extensibility"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678",
ieee80211w='1')
params['rsn_override_key_mgmt'] = 'SAE SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP GCMP-256'
params['rsn_override_mfp'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
params['rsnxe_override'] = 'f4182f0000ffffffffffffffffffffffffffeeeeeeeeeeeeeeee'
params['rsnxoe_override'] = 'dd1c506f9a2b2f0000ffffffffffffffffffffffffffeeeeeeeeeeeeeeee'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678", key_mgmt="SAE",
ieee80211w="2", ssid_protection="1",
scan_freq="2412")
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")
def test_rsn_override_sta_only(dev, apdev):
"""RSN overriding enabled only on the STA"""
check_sae_capab(dev[0])
params = hostapd.wpa2_params(ssid="test-sae",
passphrase="12345678")
params['wpa_key_mgmt'] = 'SAE'
hapd = hostapd.add_ap(apdev[0], params)
dev[0].set("sae_groups", "")
try:
dev[0].set("rsn_overriding", "1")
dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
scan_freq="2412")
finally:
dev[0].set("rsn_overriding", "0")
def test_rsn_override_compatibility_mode(dev, apdev):
"""RSN overriding and WPA3-Personal Compatibility Mode"""
check_sae_capab(dev[0])
ssid = "test-rsn-override"
params = hostapd.wpa2_params(ssid=ssid,
passphrase="12345678")
params['rsn_override_key_mgmt'] = 'SAE'
params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY'
params['rsn_override_pairwise'] = 'CCMP'
params['rsn_override_pairwise_2'] = 'GCMP-256'
params['rsn_override_mfp'] = '2'
params['rsn_override_mfp_2'] = '2'
params['beacon_prot'] = '1'
params['sae_groups'] = '19 20'
params['sae_require_mfp'] = '1'
params['sae_pwe'] = '2'
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
try:
logger.info("RSN overriding capable STA using RSNO2E")
dev[0].set("rsn_overriding", "1")
dev[0].scan_for_bss(bssid, freq=2412)
dev[0].set("sae_pwe", "2")
dev[0].set("sae_groups", "")
dev[0].connect(ssid, sae_password="12345678",
pairwise="GCMP-256", key_mgmt="SAE-EXT-KEY",
ieee80211w="2", scan_freq="2412")
hapd.wait_sta()
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
hapd.wait_sta_disconnect()
logger.info("RSN overriding capable STA using RSNOE")
dev[0].set("sae_pwe", "0")
dev[0].connect(ssid, sae_password="12345678",
pairwise="CCMP", key_mgmt="SAE",
ieee80211w="2", scan_freq="2412")
hapd.wait_sta()
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
hapd.wait_sta_disconnect()
logger.info("RSN overriding capable STA using RSNE")
dev[0].connect(ssid, psk="12345678",
pairwise="CCMP", key_mgmt="WPA-PSK",
ieee80211w="0", scan_freq="2412")
hapd.wait_sta()
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
hapd.wait_sta_disconnect()
logger.info("RSN overriding uncapable STA using RSNE")
dev[0].set("rsn_overriding", "0")
dev[0].connect(ssid, psk="12345678",
pairwise="CCMP", key_mgmt="WPA-PSK",
ieee80211w="0", scan_freq="2412")
hapd.wait_sta()
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
hapd.wait_sta_disconnect()
finally:
dev[0].set("sae_pwe", "0")
dev[0].set("rsn_overriding", "0")

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