3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-12-20 18:08:31 +01:00

Compare commits

...

558 Commits
2.7 ... master

Author SHA1 Message Date
Marcel Holtmann
3e7a8feee0 Release 3.10 2025-09-25 15:36:37 +02:00
James Prestwood
3760a49650 station: print vendor quirks (if any) when connecting/roaming
This makes it clear the BSS being selected for a connection/roam has
any quirks associated with its OUI(s) and that IWD may behave
differently based on these.
2025-08-27 12:40:50 -05:00
James Prestwood
c4d114d804 auto-t: add AP roam test for bad neighbor reports/candidate lists 2025-08-27 12:40:44 -05:00
James Prestwood
ffe79bfada station: check vendor quirk for BSS TM request candidate list
If the AP vendor has known issues with the preferred candidate list
ignore it and jump directly to requesting a neighbor report.
2025-08-27 12:40:28 -05:00
James Prestwood
c0efaf21ad station: get neighbor report on BSS TM request
If a BSS is requesting IWD roam elsewhere but does not include a
preferred candidate list try getting a neighbor report before doing
a full scan.

If the limited scan based on the candidate list comes up empty this
would previously result in IWD giving up on the AP roam entirely.
This patch also improves that behavior slightly by doing a full
scan afterwards as a last ditch effort. If no BSS's are found after
that, IWD will give up on the AP roam.
2025-08-27 12:38:34 -05:00
James Prestwood
cee079da5b handshake: use vendor quirk to disable check of replay counters
This has been a long standing issue on Aruba APs where the scan
IEs differ from the IEs received during FT. For compatibility we
have been carrying a patch to disable the replay counter check but
this isn't something that was ever acceptable for upstream. Now
with the addition of vendor quirks this check can be disabled only
for the OUI of Aruba APs.

Reported-by: Michael Johnson <mjohnson459@gmail.com>
Co-authored-by: Michael Johnson <<mjohnson459@gmail.com>
2025-08-27 12:37:54 -05:00
James Prestwood
df30309aac station: set vendor quirks into handshake object 2025-08-27 12:37:49 -05:00
James Prestwood
2fe8c13016 scan: store vendor quirks in scan_bss
As each vendor IE is parsed lookup if there are any quirks associated
with it, and store these in a bit mask.
2025-08-27 12:37:21 -05:00
James Prestwood
84666b9703 handshake: add vendor quirks into handshake object 2025-08-27 12:37:00 -05:00
James Prestwood
54c0dbb3c8 handshake: pass object to handshake_util_ap_ie_matches
This is to prepare for supporting a vendor quirk, where we'll need
the handshake to lookup if the quirk to disable a specific check.
2025-08-27 12:36:13 -05:00
James Prestwood
6e9e0928b0 vendor_quirks: implement two vendor quirks
ignore_bss_tm_candidates:
  When a BSS requests a station roam it can optionally include a
  list of BSS's that can be roamed to. IWD uses this list and only
  scans on those frequencies. In some cases though the AP's list
  contains very poor options and it would be better for IWD to
  request a full neighbor report.

replay_counter_mismatch:
  On some Aruba APs there is a mismatch in the replay counters
  between what is seen in scans versus authentications/associations.
  This difference is not allowed in the spec, therefore IWD will
  not connect. This quirk is intended to relax that check.
2025-08-27 12:31:57 -05:00
James Prestwood
a1247fe46e vendor_quirks: initial skeleton
This module will provide a database for known issues or quirks with
wireless vendors.

The vendor_quirks_append_for_oui() API is intended to be called from
scan.c when parsing vendor attributes. This will lookup any quirks
associated with the OUI provided and combine them into an existing
vendor_quirk structure. This can be repeated against all the vendor
OUI's seen in the scan then referenced later to alter IWD behavior.

In the future more critera could be added such as MAC address prefix
or more generalized IE matches e.g.

vendor_quirks_append_for_mac()
vendor_quirks_append_for_ie()
etc.
2025-08-27 12:26:03 -05:00
James Prestwood
088bb2e308 station: clear roam_freqs on delayed roam
If there were no BSS candidates found after trying to roam make
sure the old roam_freqs list gets cleared so IWD doesn't end up
scanning potentially old frequencies on the next retry.
2025-08-26 10:00:32 -05:00
James Prestwood
57dc5d843c monitor: add Cisco Meraki as a printable vendor 2025-08-26 09:38:01 -05:00
James Prestwood
8cb134f935 scan: check support before using colocated flag 2025-08-26 09:37:17 -05:00
James Prestwood
46037c428c wiphy: add comments around the driver quirks 2025-08-26 09:36:44 -05:00
James Prestwood
161de4a3ad wiphy: add driver quirk for the colocated scan flag
Some drivers do not handle the colocated scan flag very well and this
results in BSS's not being seen in scans. This of course results in
very poor behavior.

This has been seen on ath11k specifically but after some
conversations [1] on the linux-wireless mailing list others have
reported issues with iwlwifi acting similarly. Since there are many
hardware variants that use both ath11k and iwlwifi this new quirk
isn't being forced to those drivers, but let users configure IWD to
disable the flag if needed.

[1] https://lore.kernel.org/linux-wireless/d1e75a08-047d-7947-d51a-2e486efead77@candelatech.com/
2025-08-26 09:35:35 -05:00
James Prestwood
77ee863f04 auto-t: add test for channel switch during roam
In kernel 6.8 a new CMD_ASSOCIATE failure path was added which checks
if the AP has a channel switch in progress. Eariler patches update
IWD into handling this case better, and this new test exercises that.
2025-08-20 11:18:51 -05:00
James Prestwood
405d1ab77c auto-t: make waiting for channel switch configurable 2025-08-20 11:18:45 -05:00
James Prestwood
dc1589f3fe netdev: disconnect rather than deauth in FT association failure
After CSA IE parsing was added to the kernel this opened up the
possibility that associations could be rejected locally based on
the contents of this CSA IE in the AP's beacons. Overall, it was
always possible for a local rejection but this case was never
considered by IWD. The CSA-based rejection is something that can
and does happen out in the wild.

When this association rejection happens it desync's IWD and the
kernel's state:

1. IWD begins an FT roam. Authenticates successfully, then proceeds
   to calling netdev_ft_reassociate().
2. Immediately IWD transitions to a ft-roaming state and waits for
   an association response.
3. CMD_ASSOCIATE is rejected by the kernel in the ACK which IWD
   handles by sending a deauthenticate command to the kernel (since
   we have a valid authentication to the new BSS).
4. Due to a bug IWD uses the target BSSID to deauthenticate which
   the kernel rejects since it has no knowledge of this auth. This
   error is not handled or logged.
5. IWD proceeds, assuming its deauthenticated, and transitions to a
   disconnected state. The kernel remains "connected" which of course
   prevents any future connections.

A simple fix for this is to address the bug (4) in IWD that deauths
using the current BSS roam target. This is actually legacy behavior
from back when IWD used CMD_AUTHENTICATE. Today the kernel is unaware
that IWD authenticated so a deauth is not going to be effective.
Instead we can issue a CMD_DISCONNECT. This is somewhat of a large
hammer, but since the handshake and internal state has already been
modified to use the new target BSS we cannot go back and maintain the
existing connect (though it is _possible_, see the TODO in the
patch).
2025-08-20 11:18:01 -05:00
James Prestwood
755280a4cc netdev: check connected in channel switch event
In an ideal world userspace should never be getting a channel switch
event unless connected to an AP, but alas this has been seen at least
with ath10k hardware. This causes IWD to crash since the logic
assumes netdev->handshake is set.
2025-08-20 11:17:54 -05:00
Gokul Sivakumar
df2c5cf7fa doc: add STA inactive and connected time duration info to diagnostics 2025-08-07 17:59:15 -05:00
Gokul Sivakumar
fee0e5de33 netdev: parse INACTIVE_TIME and CONNECTED_TIME in netdev_get_station
These two newly parsed station info params "inactive time" and the
"connected time" would be helpful to track the duration (in ms) for
which the station was last inactive and the total duration (in s) for
which the station is currently connected to the AP.

When the wlan device is in STA mode, these fields represent the info
of this station device. And when wlan device is in AP mode, then these
fields repesents the stations that are connected to this AP device.
2025-08-06 09:33:42 -05:00
Marcel Holtmann
601d9b0e02 Release 3.9 2025-06-14 12:10:16 +02:00
James Prestwood
f209e00dde doc: add note about timeouts to Network.Connect()
Since netconfig is now part of the Connect() call from a DBus
perspective add a note indicating that this method has the potential
to take a very long time if there are issues with DHCP.
2025-06-05 10:02:28 -05:00
James Prestwood
86523b0597 auto-t: update several tests to work with netconfig refactor
Since the method return to Connect() and ConnectBssid() come after
netconfig some tests needed to be updated since they were waiting
for the method return before continuing. For timeout-based tests
specifically this caused them to fail since before they expected
the return to come before the connection was actually completed.
2025-06-05 10:02:23 -05:00
James Prestwood
85a2637fc5 auto-t: allow configurable DBus timeout/callbacks on connect{_bssid}
Let the caller specify the method timeout if there is an expectation
that it could take a long time.

For the conventional connect call (not the "bssid" debug variant) let
them pass their own callback handlers. This is useful if we don't
want to wait for the connect call to finish, but later get some
indication that it did finish either successfully or not.
2025-06-05 10:02:13 -05:00
James Prestwood
2f991918b1 station: include netconfig as part of the BSS retry logic
A netconfig failure results in a failed connection which restarts
autoconnect and prevents IWD from retrying the connection on any
other BSS's within the network as a whole. When autoconnect restarts
IWD will scan and choose the "best" BSS which is likely the same as
the prior attempt. If that BSS is somehow misconfigured as far as
DHCP goes, it will likely fail indefinitely and in turn cause IWD to
retry indefinitely.

To improve this netconfig has been adopted into the IWD's BSS retry
logic. If netconfig fails this will not result in IWD transitioning
to a disconnected state, and instead the BSS will be network
blacklisted and the next will be tried. Only once all BSS's have been
tried will IWD go into a disconnected state and start autoconnect
over.
2025-06-05 10:02:02 -05:00
James Prestwood
5b5a9b60fb station: fix DBus reply for Connect() with netconfig
When netconfig is enabled the DBus reply was being sent in
station_connect_ok(), before netconfig had even started. This would
result in a call to Connect() succeeding from a DBus perspective but
really netconfig still needed to complete before IWD transitioned
to a connected state.

Fixes: 72e7d3ceb83d ("station: Handle NETCONFIG_EVENT_FAILED")
2025-06-05 10:01:45 -05:00
James Prestwood
5287809043 network: make clearing network blacklist a separate operation
This adds a new API network_clear_blacklist() and removes this
functionality from network_connected(). This is done to support BSS
iteration when netconfig is enabled. Since a call to
network_connected() will happen prior to netconfig completing we
cannot clear the blacklist until netconfig has either passed or
failed.
2025-06-05 10:01:42 -05:00
James Prestwood
ea9ff2dcaf sae: prevent groups 21, 25, and 26 from being used
These groups are not working reliably and until that is fixed they
should be disabled.
2025-06-05 09:59:34 -05:00
James Prestwood
9dce36fe3d sae: check return on sae_send_commit()
If this fails, in some cases, -EAGAIN would be returned up to netdev
which would then assume a retry would be done automatically. This
would not in fact happen since it was an internal SAE failure which
would result in the connect method return to never get sent.

Now if sae_send_commit() fails, return -EPROTO which will cause
netdev to fail the connection.
2025-06-05 09:59:16 -05:00
Marcel Holtmann
c4718a5355 unit: Update precheck for WSC PBC test cases 2025-05-28 19:29:47 +02:00
James Prestwood
c9c8790ff2 netdev: support handling NL80211_CMD_ASSOC_COMEBACK
A BSS can temporarily reject associations and provide a delay that
the station should wait for before retrying. This is useful when
sane values are used, but taking it to the extreme an AP could
potentially request the client wait UINT32_MAX TU's which equates
to 49 days.

Either due to a bug, or worse by design, the kernel will wait for
however long that timeout is. Luckily the kernel also sends an event
to userspace with the amount of time it will be waiting. To guard
against excessive timeouts IWD will now handle this event and enforce
a maximum allowed value. If the timeout exceeds this IWD will
deauthenticate.
2025-05-28 12:06:43 -05:00
James Prestwood
d135bfc4b8 nl80211util: support parsing NL80211_ATTR_TIMEOUT 2025-05-28 12:06:36 -05:00
James Prestwood
e269beadba nl80211cmd: add NL80211_CMD_ASSOC_COMEBACK 2025-05-28 12:06:28 -05:00
James Prestwood
3e55fc855a auto-t: use renamed InitialAccessPointBusyTimeout 2025-05-19 16:38:54 -05:00
James Prestwood
c8d9936f9d station: utilize the AP_BUSY blacklist for denied auth/assoc
Specifically for the NO_MORE_STAS reason code, add the BSS to the
(now renamed) AP_BUSY blacklist to avoid roaming to this BSS for
the near future.

Since we are now handling individual reason codes differently the
whole IS_TEMPORARY_STATUS macro was removed and replaced with a
case statement.
2025-05-19 16:38:28 -05:00
James Prestwood
79940956ef docs: replace/deprecate InitialRoamRequestedTimeout
This is being replaced by InitialAccessPointBusyTimeout but will
still be supported until full removal.
2025-05-19 16:38:13 -05:00
James Prestwood
9f98c6c3c8 blacklist: rename ROAM_REQUESTED to AP_BUSY
The initial pass of this feature only envisioned BSS transition
management frames as the trigger to "roam blacklist" a BSS, hence
the original name. But some APs actually utilize status codes that
also indicate to the stations that they are busy, or not able to
handle more connections. This directly aligns with the original
motivation of the "roam blacklist" series and these events should
also trigger this type of blacklist.

First, since we will be applying this blacklist to cases other
than being told to roam, rename this reason code internally to
BLACKLIST_REASON_AP_BUSY. The config option is also being renamed
to [Blacklist].InitialAccessPointBusyTimeout while also supporting
the old config option, but warning that it is deprecated.
2025-05-19 16:37:13 -05:00
James Prestwood
93eef7b02d ap: implement pre-scanning to "unlock" frequencies
Some drivers/hardware are more strict about limiting use of
certain frequencies on startup until the regulatory domain has
been set. For most cards the only way to set the regulatory domain
is to scan and see BSS's nearby that advertise the country they
reside in.

This is particularly important for AP mode since AP's are always
emitting radiation from beacons and will not start until the desired
frequency is both enabled and allows IR. To make this process
seamless in IWD we will first check that the desired frequency is
enabled/IR and if not issue a scan to (hopefully) get the regulatory
domain set.
2025-05-19 16:36:45 -05:00
Marcel Holtmann
26ed1f8b9f Release 3.8 2025-05-07 13:41:49 +02:00
Marcel Holtmann
243db1d256 build: Require at least version 0.77 when building with external ELL 2025-05-07 12:47:42 +02:00
Marcel Holtmann
5224b0b0e7 unit: Use test precheck feature to check for kernel capabilities 2025-05-07 09:54:22 +02:00
Marcel Holtmann
3267d356d2 unit: The precheck function also takes test data as parameter 2025-05-05 20:41:56 +02:00
Marcel Holtmann
78f4e6240e unit: Use new precheck feature for storage encryption test 2025-05-05 19:37:34 +02:00
Marcel Holtmann
36b1086f60 Release 3.7 2025-05-04 19:34:32 +02:00
Marcel Holtmann
266eb405f2 build: Add test-storage to ignore list 2025-05-04 19:34:15 +02:00
James Prestwood
0a8e646231 eap: initialize vendor_id/vendor_type to zero
This fixes a compiler warning, specifically on ARM/GCC 12.2.0

src/eap.c: In function ‘eap_rx_packet’:
src/eap.c:419:57: error: ‘vendor_type’ may be used uninitialized [-Werror=maybe-uninitialized]
  419 |         (type == EAP_TYPE_EXPANDED && vendor_id == (id) && vendor_type == (t))
      |                                                         ^~
src/eap.c:429:18: note: ‘vendor_type’ was declared here
  429 |         uint32_t vendor_type;
      |                  ^~~~~~~~~~~
src/eap.c:419:49: error: ‘vendor_id’ may be used uninitialized [-Werror=maybe-uninitialized]
  419 |         (type == EAP_TYPE_EXPANDED && vendor_id == (id) && vendor_type == (t))
      |                                                 ^~
src/eap.c:428:18: note: ‘vendor_id’ was declared here
  428 |         uint32_t vendor_id;
      |                  ^~~~~~~~~
2025-05-02 12:14:37 -05:00
James Prestwood
8ebc4780ea station: fix setting an empty affinities list
A prior patch broke this by checking the return of
l_dbus_message_iter_next_entry. This was really subtle but the logic
actually relied on _not_ checking that return in order to handle
empty lists.

Instead of reverting the logic was adapted/commented to make it more
clear what the API expects from DBus. If list contains at least one
value the first element path will get set, if it contains zero
values "new_path" will be set to NULL which will then cause the
list to be cleared later on.

This both fixes the regression, and makes it clear that a zero
element list is supported and handled.
2025-04-23 09:42:48 -05:00
Marcel Holtmann
4ded663e68 unit: Fix country code assignment for test case
CC       unit/test-p2p.o
unit/test-p2p.c:344:36: error: initializer-string for array of ‘char’ truncates NUL terminator but destination lacks ‘nonstring’ attribute (4 chars into 3 available) [-Werror=unterminated-string-initialization]
  344 |                         .country = "XX\x04",
      |                                    ^~~~~~~~
2025-04-19 22:49:53 +02:00
James Prestwood
c00bc3a065 eap-mschapv2: Fix leak of state->user on error path
Fixes: 6dc5d2c3ecb6 ("eap-mschapv2: Load credentials obtained from agent")
2025-04-16 14:58:00 -05:00
James Prestwood
f469db8a95 station: check return when advancing iterator
Fixes: f4ec1ee509fc ("station: add Affinities DBus property")
2025-04-16 14:58:00 -05:00
James Prestwood
c3a27354ff unit: add test-storage
For now, a single test for __storage_decrypt that ensures an
invalid length fails as expected.
2025-04-16 14:58:00 -05:00
James Prestwood
d927fd07c1 storage: add length check in __storage_decrypt
The length of EncryptedSecurity was assumed to be at least 16 bytes
and anything less would underflow the length to l_malloc.

Fixes: 01cd8587606b ("storage: implement network profile encryption")
2025-04-16 14:58:00 -05:00
James Prestwood
8dff156eb6 monitor: add size check for interworking IE parsing
Fixes: e0c9b68467fa ("monitor: parse/print HS2.0/WFA IEs")
2025-04-16 14:58:00 -05:00
James Prestwood
e5c41a8024 unit: add test for duplicate URI elements 2025-04-16 14:58:00 -05:00
James Prestwood
603d6b2881 dpp-util: fail on duplicate values in URI
The MAC and version elements weren't super critical but the channel
and bootstrapping key elements would result in memory leaks if there
were duplicates.

This patch now will not allow duplicate elements in the URI.

Fixes: f7f602e1b1e7 ("dpp-util: add URI parsing")
2025-04-16 14:58:00 -05:00
James Prestwood
d1aa4009bc scan: fix out of bound array access for survey results
The survey arrays were exactly the number of valid channels for a
given band (e.g. 14 for 2.4GHz) but since channels start at 1 this
means that the last channel for a band would overflow the array.

Fixes: 35808debaefd ("scan: use GET_SURVEY for SNR calculation in ranking")
2025-04-16 14:58:00 -05:00
James Prestwood
3c5081c7a6 monitor: fix spelling Exausted -> Exhausted
Caught by codespell

Fixes: 83a2457550e7 ("monitor: add support for limiting PCAP size/count")
2025-04-16 14:58:00 -05:00
Marcel Holtmann
7d5bcd738b Release 3.6 2025-04-02 15:05:43 +02:00
James Prestwood
0a93c55552 netdev: implement PMKSA for fullmac drivers
Supporting PMKSA on fullmac drivers requires that we set the PMKSA
into the kernel as well as remove it. This can now be triggered
via the new PMKSA driver callbacks which are implemented and set
with this patch.
2025-04-01 11:15:03 -05:00
James Prestwood
7f9ea7640d handshake: use pmksa_cache_free 2025-04-01 11:14:40 -05:00
James Prestwood
c52d913f20 pmksa: add driver callbacks and pmksa_cache_free
In order to support fullmac drivers the PMKSA entries must be added
and removed from the kernel. To accomplish this a set of driver
callbacks will be added to the PMKSA module. In addition a new
pmksa_cache_free API will be added whos only purpose is to handle
the removal from the kernel.
2025-04-01 11:11:08 -05:00
James Prestwood
651b647570 netdev: remove/update some iwd_notice logs
The iwd_notice function was more meant for special purpose events
not general debug prints. For these error conditions we should be
using l_warn. For the informational "External Auth to SSID" log
we already print this information when connecting from station. In
addition there are logs when performing external auth so it should
be very obvious external auth is being used without this log.
2025-04-01 11:10:39 -05:00
James Prestwood
8cf9734d2b netdev: don't set CQM thresholds for fullmac cards
Since roaming is handled by the firmware setting CQM thresholds for
roaming is pointless.
2025-04-01 11:10:26 -05:00
James Prestwood
d70fbade44 netdev: fix invalid read after netdev_free
The netdev frame watches got cleaned up upon the interface going down
which works if the interface is simply being toggled but when IWD
shuts down it first shuts down the interface, then immediately frees
netdev. If a watched frame arrives immediately after that before the
interface shutdown callback it will reference netdev, which has been
freed.

Fix this by clearing out the frame watches in netdev_free.

==147== Invalid read of size 8
==147==    at 0x408ADB: netdev_neighbor_report_frame_event (netdev.c:4772)
==147==    by 0x467C75: frame_watch_unicast_notify (frame-xchg.c:234)
==147==    by 0x4E28F8: __notifylist_notify (notifylist.c:91)
==147==    by 0x4E2D37: l_notifylist_notify_matches (notifylist.c:204)
==147==    by 0x4A1388: process_unicast (genl.c:844)
==147==    by 0x4A1388: received_data (genl.c:972)
==147==    by 0x49D82F: io_callback (io.c:105)
==147==    by 0x49C93C: l_main_iterate (main.c:461)
==147==    by 0x49CA0B: l_main_run (main.c:508)
==147==    by 0x49CA0B: l_main_run (main.c:490)
==147==    by 0x49CC3F: l_main_run_with_signal (main.c:630)
==147==    by 0x4049EC: main (main.c:614)
2025-04-01 11:06:40 -05:00
James Prestwood
f0e515b6ff doc: document InitialRoamRequestedTimeout 2025-04-01 11:06:29 -05:00
James Prestwood
47ef40d645 auto-t: add tests for AP roam blacklisting 2025-04-01 11:06:21 -05:00
James Prestwood
9e10efbef5 station: roam blacklist AP even mid-roam
If an AP directed roam frame comes in while IWD is roaming its
still valuable to parse that frame and blacklist the BSS that
sent it.

This can happen most frequently during a roam scan while connected
to an overloaded BSS that is requesting IWD roams elsewhere.
2025-04-01 11:06:02 -05:00
James Prestwood
224afbb9ca station: roam blacklist BSS's, and consider when roaming
If the BSS is requesting IWD roam elsewhere add this BSS to the
blacklist using BLACKLIST_REASON_ROAM_REQUESTED. This will lower
the chances of IWD roaming/connecting back to this BSS in the
future.

This then allows IWD to consider this blacklist state when picking
a roam candidate. Its undesireable to fully ban a roam blacklisted
BSS, so some additional sorting logic has been added. Prior to
comparing based on rank, BSS's will be sorted into two higher level
groups:

Above Threshold - BSS is above the RoamThreshold
Below Threshold - BSS is below the RoamThreshold

Within each of these groups the BSS may be roam blacklisted which
will position it at the bottom of the list within its respecitve
group.
2025-04-01 11:05:22 -05:00
James Prestwood
bf69e6210c netdev: add netdev_get_low_signal_threshold 2025-04-01 10:55:10 -05:00
James Prestwood
258482d509 blacklist: add new blacklist reason, ROAM_REQUESTED
This adds a new (less severe) blacklist reason as well as an option
to configure the timeout. This blacklist reason will be used in cases
where a BSS has requested IWD roam elsewhere. At that time a new
blacklist entry will be added which will be used along with some
other criteria to determine if IWD should connect/roam to that BSS
again.

Now that we have multiple blacklist reasons there may be situations
where a blacklist entry already exists but with a different reason.
This is going to be handled by the reason severity. Since we have
just two reasons we will treat a connection failure as most severe
and a roam requested as less severe. This leaves us with two
possible situations:

1. BSS is roam blacklisted, then gets connection blacklisted:
   The reason will be "promoted" to connection blacklisted.

2. BSS is connection blacklisted, then gets roam blacklisted:
   The blacklist request will be ignored
2025-04-01 10:54:04 -05:00
James Prestwood
1caad4ca88 blacklist: fix pruning to remove the entry if its expired
When pruning the list check_if_expired was comparing to the maximum
amount of time a BSS can be blacklisted, not if the current time had
exceeded the expirationt time. This results in blacklist entries
hanging around longer than they should, which would result in them
poentially being blacklisted even longer if there was another reason
to blacklist in the future.

Instead on prune check the actual expiration and remove the entry if
its expired. Doing this removes the need to check any of the times
in blacklist_contains_bss since prune will remove any expired entries
correctly.
2025-04-01 10:53:18 -05:00
James Prestwood
59464a0ca4 blacklist: include a blacklist reason
To both prepare for some new blacklisting behavior and allow for
easier consolidation of the network-specific blacklist include a
reason enum for each entry. This allows IWD to differentiate
between multiple blacklist types. For now only the existing
"permanent" type is being added which prevents connections to that
BSS via autoconnect until it expires.
2025-04-01 10:52:25 -05:00
James Prestwood
93b25c87d6 auto-t: add test for disabling the timeout blacklist 2025-04-01 10:27:42 -05:00
James Prestwood
e971ef71d5 station: always add BSS to network blacklist on failure
Allowing the timeout blacklist to be disabled has introduced a bug
where a failed connection will not result in the BSS list to be
traversed. This causes IWD to retry the same BSS over and over which
be either a) have some issue preventing a connection or b) may simply
be unreachable/out of range.

This is because IWD was inherently relying on the timeout blacklist
to flag BSS's on failures. With it disabled there was nothing to tell
network_bss_select that we should skip the BSS and it would return
the same BSS indefinitely.

To fix this some of the blacklisting logic was re-worked in station.
Now, a BSS will always get network blacklisted upon a failure. This
allows network.c to traverse to the next BSS upon failure.

For auth/assoc failures we will then only timeout blacklist under
certain conditions, i.e. the status code was not in the temporary
list.

Fixes: 77639d2d452e ("blacklist: allow configuration to disable the blacklist")
2025-04-01 10:27:13 -05:00
Marcel Holtmann
bff5006b38 Release 3.5 2025-03-26 10:47:40 +01:00
James Prestwood
ea571861d6 auto-t: update scapy imports for newer version
Something changed between scapy versions and now the modules
being imported don't exist.
2025-03-07 10:29:19 -06:00
James Prestwood
f3e4263f51 doc: document how to disable blacklisting 2025-03-04 08:43:54 -06:00
James Prestwood
77639d2d45 blacklist: allow configuration to disable the blacklist
Certain use cases may not need or want this feature so allowing it to
be disabled is a much cleaner way than doing something like setting
the timeouts very low.

Now [Blacklist].InitialTimeout can be set to zero which will prevent
any blacklisting.

In addition some other small changes were added:
 - Warn if the multiplier is 0, and set to 1 if so.
 - Warn if the initial timeout exceeds the maximum timeout.
 - Log if the blacklist is disabled
 - Use L_USEC_PER_SEC instead of magic numbers.
2025-03-04 08:40:53 -06:00
James Prestwood
1662707f22 doc: document [DriverQuirks].SaeDisable 2025-02-13 09:27:20 -06:00
James Prestwood
5f4bf2a5e5 wiphy: add driver quirk to disable SAE
SAE/WPA3 is completely broken on brcmfmac, at least without a custom
kernel patch which isn't included in many OS distributions. In order
to help with this add a driver quirk so devices with brcmfmac can
utilize WPA2 instead of WPA3 and at least connect to networks at
this capacity until the fix is more widely distributed.
2025-02-13 09:26:17 -06:00
Marcel Holtmann
40af18f96a Release 3.4 2025-02-11 00:09:12 +01:00
Marcel Holtmann
ab4fa30c7e build: Require at least version 0.72 when building with external ELL 2025-02-10 23:57:46 +01:00
Marcel Holtmann
43f73823ec build: Include extra files for ELL test extensions 2025-02-10 23:02:10 +01:00
Marcel Holtmann
f4439fd2b6 build: Enable support for TAP, the Test Anything Protocol 2025-02-07 23:01:37 +01:00
James Prestwood
bf82aff039 handshake: add more debugging around PMKSA caching
Instead of just printing the PMKSA pointer separate this into two
separate debug messages, one for if the PMKSA exists and the other
if it does not. In addition print out the MAC of the AP so we have
a reference of which PMKSA this is.
2025-01-06 09:37:14 -06:00
Marcel Holtmann
4b535cee1f Release 3.3 2024-12-20 08:51:07 +01:00
James Prestwood
7144741537 netdev: destroy auth-proto after external auth
With external auth there is no associate event meaning the auth proto
never gets freed, which prevents eapol from starting inside the
OCI callback. Check for this specific case and free the auth proto
after signaling that external auth has completed.
2024-12-19 23:57:21 -06:00
James Prestwood
64b872f363 monitor: add --pcap-size,--pcap-count
The user can now limit the size and count of PCAP files iwmon will
create. This allows iwmon to run for long periods of time without
filling up disk space.
2024-12-17 11:26:38 -06:00
James Prestwood
83a2457550 monitor: add support for limiting PCAP size/count
This implements support for "rolling captures" by allowing iwmon to
limit the PCAP file size and number of PCAP's that are created.
This is a useful feature when long term monitoring is needed. If
there is some rare behavior requiring iwmon to run for days, months,
or longer the resulting PCAP file would become quite large and fill
up disk space.

When enabled (command line arguments in subsequent patch) the PCAP
file size is checked on each write. If it exceeds the limit a new
PCAP file will be created. Once the number of old PCAP files reaches
the set limit the oldest PCAP will be removed from disk.
2024-12-17 11:24:12 -06:00
James Prestwood
43f895142c monitor: track current PCAP size
This will come into play when support for rolling captures is
added to iwmon.
2024-12-17 11:23:56 -06:00
James Prestwood
c352b35bf1 monitor: add --time-format,-t option
For syncing iwmon captures with other logging its useful to
timestamp in some absolute format like UTC. This adds an
option which allows the user to specify what time format to
show. For now support:

delta - (default) The time delta between the first packet
        and the current packet.
utc   - The packet time in UTC
2024-12-17 11:22:03 -06:00
James Prestwood
d4bba5c838 wiphy: add info print for MulticastRxDisabled quirk
This was forgotten in the prior patch set. It does not change any
behavior but just adds this to the driver flags debug print when
IWD starts up.
2024-12-17 11:21:28 -06:00
Marcel Holtmann
1dd9f94713 Release 3.2 2024-11-25 19:04:47 +01:00
James Prestwood
c458e6612d doc: document [DriverQuirks].MulticastRxDisable 2024-11-25 11:47:14 -06:00
James Prestwood
45db339dcd dpp: use wiphy_supports_multicast_rx
The ath10k driver has shown some performance issues, specifically
packet loss, when frame watches are registered with the multicast
RX flag set. This is relevant for DPP which registers for these
when DPP starts (if the driver supports it). This has only been
observed when there are large groups of clients all using the same
wifi channel so its unlikely to be much of an issue for those using
IWD/ath10k and DPP unless you run large deployments of clients.

But for large deployments with IWD/ath10k we need a way to disable
the multicast RX registrations. Now, with the addition of
wiphy_supports_multicast_rx we can both check that the driver
supports this as well as if its been disabled by the driver quirk.
2024-11-25 11:47:07 -06:00
James Prestwood
887d8c8fe8 wiphy: add driver quirk for disabling multicast rx (and helper)
This driver quirk and associated helper API lets other modules both
check if multicast RX is supported, and if its been disabled via
the driver quirk setting.
2024-11-25 11:46:53 -06:00
James Prestwood
c6932efa30 wiphy: make "wiphy" const in wiphy_has_ext_feature 2024-11-25 11:46:49 -06:00
James Prestwood
f3ba82b0e1 doc: document DisablePMKSA option 2024-11-25 08:55:16 -06:00
James Prestwood
a26fcd8f2d auto-t: add PMKSA tests
Adds a test for just PMKSA and testing expiration as well as includes
some PMKSA tests in the SAE roaming test to ensure FT/reassociation
works.
2024-11-25 08:54:57 -06:00
James Prestwood
ab49b404fd station: support PMKSA connections
The actual connection piece of this is very minimal, and only
requires station to check if there is a PMKSA cached, and if so
include the PMKID in the RSNE. Netdev then takes care of the rest.

The remainder of this patch is the error handling if a PMKSA
connection fails with INVALID_PMKID. In this case IWD should retry
the same BSS without PMKSA.

An option was also added to disable PMKSA if a user wants to do
that. In theory PMKSA is actually less secure compared to SAE so
it could be something a user wants to disable. Going forward though
it will be enabled by default as its a requirement from the WiFi
alliance for WPA3 certification.
2024-11-25 08:53:01 -06:00
James Prestwood
9bc71b2853 station: hold reference to handshake object
To prepare for PMKSA support station needs access to the handshake
object. This is because if PMKSA fails due to an expired/missing
PMKSA on the AP station should retry using the standard association.
This poses a problem currently because netdev frees the handshake
prior to calling the connect callback.
2024-11-25 08:52:21 -06:00
James Prestwood
5b104967ce netdev: add support to use PMKSA over SAE if available
This was quite simple and only requiring caching the PMKSA after a
successful handshake, and using the correct authentication type
for connections if we have a prior PMKSA cached.

This is only being added for initial SAE associations for now since
this is where we gain the biggest improvement, in addition to the
requirement by the WiFi alliance to label products as "WPA3 capable"
2024-11-25 08:51:28 -06:00
James Prestwood
4680c0c13b handshake: add handshake_state_remove_pmksa
This is needed in order to clear the PMKSA from the handshake state
without actually putting it back into the cache. This is something
that will be needed in case the AP rejects the association due to
an expired (or forgotten) PMKSA.
2024-11-25 08:50:59 -06:00
Denis Kenzior
c36358cc7c handshake: Add pmksa setter & stealer
The majority of this patch was authored by Denis Kenzior, but
I have appended setting the PMK inside handshake_state_set_pmksa
as well as checking if the pmkid exists in
handshake_state_steal_pmkid.

Authored-by: Denis Kenzior <denkenz@gmail.com>
Authored-by: James Prestwood <prestwoj@gmail.com>
2024-11-25 08:46:51 -06:00
Denis Kenzior
235f6e5f14 pmksa: Add debugging 2024-11-25 08:41:31 -06:00
Denis Kenzior
980e132f48 unit: Add basic pmksa test 2024-11-25 08:37:28 -06:00
Denis Kenzior
900aa5810e pmksa: Add skeleton 2024-11-25 08:34:29 -06:00
James Prestwood
8cf83d6620 auto-t: update testSAE to disable PMKSA
There are quite a few tests here for various scenarios and PMKSA
throws a wrench into that. Rather than potentially breaking the
tests in attempt to get them working with PMKSA, just disable PMKSA.
2024-11-25 08:34:07 -06:00
James Prestwood
ee52bc60ff auto-t: add pmksa_flush() to hostapd module 2024-11-25 08:33:57 -06:00
James Prestwood
3f4a29651e auto-t: always initialize StationDebug in Device class
Since IWD doesn't utilize DBus signals in "normal" operations its
fine to lazy initialize any of the DBus interfaces since properties
can be obtained as needed with Get/GetAll.

For test-runner though StationDebug uses signals for debug events
and until the StationDebug class is initialized (via a method call
or property access) all signals will be lost. Fix this by always
initializing the StationDebug interface when a Device class is
initialized.
2024-11-25 08:33:44 -06:00
James Prestwood
f58cad8cd9 unit: update use of handshake_state with ref/unref 2024-11-25 08:33:30 -06:00
James Prestwood
b9c3feb198 handshake: add ref counting to handshake_state
This adds a ref count to the handshake state object (as well as
ref/unref APIs). Currently IWD is careful to ensure that netdev
holds the root reference to the handshake state. Other modules do
track it themselves, but ensure that it doesn't get referenced
after netdev frees it.

Future work related to PMKSA will require that station holds a
references to the handshake state, specifically for retry logic,
after netdev is done with it so we need a way to delay the free
until station is also done.
2024-11-25 08:32:03 -06:00
James Prestwood
94ebc9d90b station: print client count in scan results 2024-11-20 11:51:32 -06:00
James Prestwood
b0759ebbb2 doc: document [Rank].HighUtilization/StationCount thresholds 2024-11-20 11:51:23 -06:00
James Prestwood
f2ac45eb52 scan: add ranking modifiers for utilization/station count
The utilization rank factor already existed but was very rigid
and only checked a few values. This adds the (optional) ability
to start applying an exponentially decaying factor to both
utilization and station count after some threshold is reached.

This area needs to be re-worked in order to support very highly
loaded networks. If a network either doesn't support client
balancing or does it poorly its left up to the clients to choose
the best BSS possible given all the information available. In
these cases connecting to a highly loaded BSS may fail, or result
in a disconnect soon after connecting. In these cases its likely
better for IWD to choose a slightly lower RSSI/datarate BSS over
the conventionally 'best' BSS in order to aid in distributing
the network load.

The thresholds are currently optional and not enabled by default
but if set they behave as follows:

If the value is above the threshold it is mapped to an integer
between 0 and 30. (using a starting range of <value> - 255).
This integer is then used to index in the exponential decay table
to get a factor between 1 and 0. This factor is then applied to
the rank.

Note that as the value increases above the threshold the rank
will be increasingly effected, as is expected for an exponential
function. These option should be used with care as it may have
unintended consequences, especially with very high load networks.
i.e. you may see IWD roaming to BSS's with much lower signal if
there are high load BSS's nearby.

To maintain the existing behavior if there is no utilization
factor set in main.conf the legacy thresholds/factors will be
used.
2024-11-20 11:47:25 -06:00
James Prestwood
7c5b40ff6b scan: parse station count from BSS load IE
This will be used in BSS ranking
2024-11-20 11:47:15 -06:00
James Prestwood
7465abe5f8 network: use util_exponential_decay 2024-11-20 11:46:46 -06:00
James Prestwood
a910a21beb util: add util_exponential_decay
This is copied from network.c that uses a static table to lookup
exponential decay values by index (generated from 1/pow(n, 0.3)).
network.c uses this for network ranking but it can be useful for
BSS ranking as well if you need to apply some exponential backoff
to a value.
2024-11-20 11:46:43 -06:00
James Prestwood
c40e665094 unit: add linear mapping test 2024-11-20 11:39:12 -06:00
James Prestwood
bb57d61add util: add util_linear_map
This has been needed elsewhere but generally shortcuts could be
taken mapping with ranges starting/ending with zero. This is a
more general linear mapping utility to map values between any
two ranges.
2024-11-20 11:37:14 -06:00
Rudi Heitbaum
fc2965649c anqputil: fix -std=c23 build failure
gcc-15 switched to -std=c23 by default:

    https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=55e3bd376b2214e200fa76d12b67ff259b06c212

As a result `iwd` fails the build as:

    ../src/anqputil.c:134:24: error: incompatible types when returning type '_Bool' but 'char **' was expected
      134 |                 return false;
          |                        ^~~~~

Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
2024-11-20 11:36:28 -06:00
Rudi Heitbaum
fa25de4ad1 crypto: fix -std=c23 build failure
gcc-15 switched to -std=c23 by default:

    https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=55e3bd376b2214e200fa76d12b67ff259b06c212

As a result `iwd` fails the build as:

    ../src/crypto.c:1215:24: error: incompatible types when returning type '_Bool' but 'struct l_ecc_point *' was expected
     1215 |                 return false;
          |                        ^~~~~

Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
2024-11-20 11:36:20 -06:00
Sergei Trofimovich
901305dcdd wired: fix -std=c23 build failure
gcc-15 switched to -std=c23 by default:

    https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=55e3bd376b2214e200fa76d12b67ff259b06c212

As a result `iwd` fails the build as:

    wired/ethdev.c: In function 'pae_open':
    wired/ethdev.c:340:55:
      error: passing argument 4 of 'l_io_set_read_handler'
        from incompatible pointer type [-Wincompatible-pointer-types]
      340 |         l_io_set_read_handler(pae_io, pae_read, NULL, pae_destroy);
          |                                                       ^~~~~~~~~~~
          |                                                       |
          |                                                       void (*)(void)
    In file included from ...-ell-0.70-dev/include/ell/ell.h:19,
                     from wired/ethdev.c:38:
    ...-ell-0.70-dev/include/ell/io.h:33:68:
      note: expected 'l_io_destroy_cb_t' {aka 'void (*)(void *)'}
        but argument is of type 'void (*)(void)'
       33 |                                 void *user_data, l_io_destroy_cb_t destroy);
          |                                                  ~~~~~~~~~~~~~~~~~~^~~~~~~

C23 changed the meaning of `void (*)()` from partially defined prototype
to `void (*)(void)`.
2024-11-20 11:34:03 -06:00
James Prestwood
b4a4495537 monitor: add better info about the country code IE
The 3rd byte of the country code was being printed as ASCII but this
byte isn't always a printable character. Instead we can check what
the value is and describe what it means from the spec.
2024-11-13 11:40:13 -06:00
Marcel Holtmann
ccd91fe556 Release 3.1 2024-11-07 19:36:18 +01:00
James Prestwood
e89e4d692c general: add .codespellrc file
This is what was used to get clean output from codespell. Common
words/abbreviations and exclusion were added that come up in the
code base.
2024-11-07 19:11:59 +01:00
James Prestwood
0868418ad1 treewide: fix spelling mistakes 2024-11-07 19:11:59 +01:00
James Prestwood
d81de65533 unit: add test with list of known unsupported frequencies
These frequencies were seen being advertised by a driver and IWD has
no operating class/channel mapping for them. Specifically 5960 was
causing issues due to a few bugs and mapping to channel 2 of the 6ghz
band. Those bugs have now been resolved.

If these frequencies can be supported in a clean manor we can remove
this test, but until then ensure IWD does not parse them.
2024-10-24 16:00:36 -05:00
James Prestwood
65073ffcfa util: warn on invalid channels when iterating a frequency set
This should not happen but if it does we should alert the user.
2024-10-24 12:11:39 -05:00
James Prestwood
d0b9fc84b5 band: check the operating class band before checking e4
After the band is established we check the e4 table for the channel
that matches. The problem here is we will end up checking all the
operating classes, even those that are not within the band that was
determined. This could result in false positives and return a
channel that doesn't make sense.
2024-10-24 12:11:31 -05:00
James Prestwood
e0727bfeb6 nl80211util: check band when parsing supported frequencies
When the frequencies/channels were parsed there was no check that the
resulting band matched what was expected. Now, pass the band object
itself in which has the band set to what is expected.
2024-10-24 12:10:27 -05:00
James Prestwood
8e10e00904 band: correct oper class 136 starting frequency
This should be 5925, not 5950
2024-10-24 12:10:23 -05:00
James Prestwood
a2b2f66c4c station: check support for all sysfs settings
If IPv6 is disabled or not supported at the kernel level writing the
sysfs settings will fail. A few of them had a support check but this
patch adds a supported bool to the remainder so we done get errors
like:

Unable to write drop_unsolicited_na to /proc/sys/net/ipv6/conf/wlan0/drop_unsolicited_na
2024-10-24 09:12:12 -05:00
James Prestwood
ca9b7ccaf6 dpp: tie frame registration to DPP state
Similar to several other modules DPP registers for its frame
watches on init then ignores anything is receives unless DPP
is actually running.

Due to some recent issues surrounding ath10k and multicast frames
it was discovered that simply registering for multicast RX frames
causes a significant performance impact depending on the current
channel load.

Regardless of the impact to a single driver, it is actually more
efficient to only register for the DPP frames when DPP starts
rather than when IWD initializes. This prevents any of the frames
from hitting userspace which would otherwise be ignored.

Using the frame-xchg group ID's we can only register for DPP
frames when needed, then close that group and the associated
frame watches.
2024-10-24 09:09:42 -05:00
James Prestwood
354bce64dd frame-xchg: add DPP frame group 2024-10-24 09:09:38 -05:00
James Prestwood
ff4edacb42 frame-xchg: add multicast RX flag argument
DPP optionally uses the multicast RX flag for frame registrations but
since frame-xchg did not support that, it used its own registration
internally. To avoid code duplication within DPP add a flag to
frame_watch_add in order to allow DPP to utilize frame-xchg.
2024-10-24 09:09:25 -05:00
James Prestwood
a6edf6f31e network: fix OWE transition BSS selection
The selection loop was choosing an initial candidate purely for
use of the "fallback_to_blacklist" flag. But we have a similar
case with OWE transitional networks where we avoid the legacy
open network in preference for OWE:

/* Don't want to connect to the Open BSS if possible */
if (!bss->rsne)
	continue;

If no OWE network gets selected we may iterate all BSS's and end
the loop, which then returns NULL.

To fix this move the blacklist check earlier and still ignore any
BSS's in the blacklist. Also add a new flag in the selection loop
indicating an open network was skipped. If we then exhaust all
other BSS's we can return this candidate.
2024-10-23 17:13:36 -05:00
James Prestwood
31787e3788 network: don't allow connection to OWE AKM if disabled 2024-10-23 17:12:57 -05:00
James Prestwood
e98a76aefb wiphy: add OweDisable driver quirk
Some drivers like brcmfmac don't support OWE but from userspace its
not possible to query this information. Rather than completely
blacklist brcmfmac we can allow the user to configure this and
disable OWE in IWD.
2024-10-23 17:07:27 -05:00
Denis Kenzior
4a04d41409 treewide: Comply with doc/coding-style.txt M13 2024-10-23 16:57:28 -05:00
Marcel Holtmann
8bb22a722b Release 3.0 2024-10-20 15:00:20 +02:00
James Prestwood
c459dc75c0 band: add "GB" as a valid alpha2 code
The "UK" alpha2 code is not the official code for the United Kingdom
but is a "reserved" code for compatibility. The official alpha2 is
"GB" which is being added to the EU list. This fixes issues parsing
neighbor reports, for example:

src/station.c:parse_neighbor_report() Neighbor report received for xx:xx:xx:xx:xx:xx: ch 136 (oper class 3), MD not set
Failed to find band with country string 'GB 32' and oper class 3, trying fallback
src/station.c:station_add_neighbor_report_freqs() Ignored: unsupported oper class
2024-10-08 11:14:08 -05:00
Vivek Das Mohapatra
1a554a300d mpdu: tolerate technically illegal but harmless cloned IEs 2024-10-07 13:26:07 -05:00
Vivek Das Mohapatra
6cc6a8a2cb unit: add a test for harmless IE clones
Test handling of technically illegal but harmless cloned IEs.
Based on real traffic captured from retail APs.

As cloned IEs are now allowed the

  "/IE order/Bad (Duplicate + Out of Order IE) 1"

test payload has been altered to be more-wrong so it still fails
verification as expected.
2024-10-07 13:19:38 -05:00
James Prestwood
b0a011d8f4 netdev: fix crash in the RSSI polling fallback workaround
Prior to adding the polling fallback this code path was only used for
signal level list notifications and netdev_rssi_polling_update() was
structured as such, where if the RSSI list feature existed there was
nothing to be done as the kernel handled the notifications.

For certain mediatek cards this is broken, hence why the fallback was
added. But netdev_rssi_polling_update() was never changed to take
this into account which bypassed the timer cleanup on disconnections
resulting in a crash when the timer fired after IWD was disconnected:

iwd: ++++++++ backtrace ++++++++
iwd: #0  0x7b5459642520 in /lib/x86_64-linux-gnu/libc.so.6
iwd: #1  0x7b54597aedf4 in /lib/x86_64-linux-gnu/libc.so.6
iwd: #2  0x49f82d in l_netlink_message_append() at ome/jprestwood/iwd/ell/netlink.c:825
iwd: #3  0x4a0c12 in l_genl_msg_append_attr() at ome/jprestwood/iwd/ell/genl.c:1522
iwd: #4  0x405c61 in netdev_rssi_poll() at ome/jprestwood/iwd/src/netdev.c:764
iwd: #5  0x49cce4 in timeout_callback() at ome/jprestwood/iwd/ell/timeout.c:70
iwd: #6  0x49c2ed in l_main_iterate() at ome/jprestwood/iwd/ell/main.c:455 (discriminator 2)
iwd: #7  0x49c3bc in l_main_run() at ome/jprestwood/iwd/ell/main.c:504
iwd: #8  0x49c5f0 in l_main_run_with_signal() at ome/jprestwood/iwd/ell/main.c:632
iwd: #9  0x4049ed in main() at ome/jprestwood/iwd/src/main.c:614
iwd: #10 0x7b5459629d90 in /lib/x86_64-linux-gnu/libc.so.6
iwd: #11 0x7b5459629e40 in /lib/x86_64-linux-gnu/libc.so.6
iwd: +++++++++++++++++++++++++++

To fix this we need to add checks for the cqm_poll_fallback flag in
netdev_rssi_polling_update().
2024-10-03 21:32:23 -05:00
James Prestwood
a27b7823df manager: fix UseDefaultInterface warning
This logic was incorrect here, we only want to print if the option
is used, not if its unset.
2024-09-25 09:52:38 -05:00
Denis Kenzior
14b9291490 sae: Allow ability to force Group 19 / Hunt and Peck 2024-09-22 16:00:04 -05:00
Denis Kenzior
354200f9da netdev: external auth support
Certain FullMAC drivers do not expose CMD_ASSOCIATE/CMD_AUTHENTICATE,
but lack the ability to fully offload SAE connections to the firmware.
Such connections can still be supported on such firmware by using
CMD_EXTERNAL_AUTH & CMD_FRAME.  The firmware sets the
NL80211_FEATURE_SAE bit (which implies support for CMD_AUTHENTICATE, but
oh well), and no other offload extended features.

When CMD_CONNECT is issued, the firmware sends CMD_EXTERNAL_AUTH via
unicast to the owner of the connection.  The connection owner is then
expected to send SAE frames with the firmware using CMD_FRAME and
receive authenticate frames using unicast CMD_FRAME notifications as
well.  Once SAE authentication completes, userspace is expected to
send a final CMD_EXTERNAL_AUTH back to the kernel with the corresponding
status code.  On failure, a non-0 status code should be used.

Note that for historical reasons, SAE AKM sent in CMD_EXTERNAL_AUTH is
given in big endian order, not CPU order as is expected!
2024-09-22 15:59:20 -05:00
James Prestwood
acc5daf0e2 netdev: allow empty TX/RX bitrate attributes
The TX or RX bitrate attributes can contain zero nested attributes.
This causes netdev_parse_bitrate() to fail, but this shouldn't then
cause the overall parsing to fail (we just don't have those values).

Fix this by continuing to parse attributes if either the TX/RX
bitrates fail to parse.
2024-09-20 10:26:53 -05:00
Marcel Holtmann
5c22ab6621 Release 2.22 2024-09-11 17:49:36 +02:00
James Prestwood
af99fbb6c0 station: fix printing uint64_t by using PRIx64
This fixed non 64-bit builds. In addition the formatting for the
seconds integer was changed to %d, since its an int.
2024-09-11 09:44:46 -05:00
James Prestwood
4b2c6de45c station: fix crash if affinities watch gets removed
If the affinity watch is removed by setting an empty list the
disconnect callback won't be called which was the only place
the watch ID was cleared. This resulted in the next SetProperty call
to think a watch existed, and attempt to compare the sender address
which would be NULL.

The watch ID should be cleared inside the destroy callback, not
the disconnect callback.
2024-09-10 19:42:03 -05:00
James Prestwood
30cc3ecf7b station: emit property changed for connected AP on roaming
This was only done for connecting states, but needs to also be done
for roaming.
2024-09-10 19:42:03 -05:00
Marcel Holtmann
87a8884f25 Release 2.21 2024-09-09 09:09:29 +02:00
Marcel Holtmann
4f2bf0b0a6 build: Require at least version 0.69 when building with external ELL 2024-09-09 08:54:10 +02:00
James Prestwood
184c3efcb3 dpp: set cap on the PKEX timeout, and reduce once PKEX finishes
If we scan a huge number of frequencies the PKEX timeout can get
rather large. This was overlooked in a prior patch who's intent
was to reduce the PKEX time, but in these cases it increased it.
Now the timeout will be capped at 2 minutes, but will still be
as low as 10 seconds for a single frequency.

In addition there was no timer reset once PKEX was completed.
This could cause excessive waits if, for example, the peer left
the channel mid-authentication. IWD would just wait until the
long PKEX timeout to eventually reset DPP. Once PKEX completes
we can assume that this peer will complete authentication quickly
and if not, we can fail.
2024-09-08 17:26:54 -05:00
James Prestwood
3f06d0128a scan: check pending requests after regdom update
While there is proper handling for a regdom update during a
TRIGGER_SCAN scan, prior to NEW_SCAN_RESULTS there is no such
handling if the regdom update comes in during a GET_SCAN or
GET_SURVEY.

In both the 6ghz and non-6ghz code paths we have some issues:
  - For non-6ghz devices, or regdom updates that did not enable
    6ghz the wiphy state watch callback will automatically issues
    another GET_SURVEY/GET_SCAN without checking if there was
    already one pending. It does this using the current scan request
    which gets freed by the prior GET_SCAN/GET_SURVEY calls when
    they complete, causing invalid reads when the subsequent calls
    finish.
 - If 6ghz was enabled by the update we actually append another
   trigger command to the list and potentially run it if its the
   current request. This also will end up in the same situation as
   the request is freed by the pending GET_SURVEY/GET_SCAN calls.

For the non-6ghz case there is little to no harm in ignoring the
regdom update because its very unlikely it changed the allowed
frequencies.

For the 6ghz case we could potentially handle the new trigger scan
within get_scan_done, but thats beyond the scope of this change
and is likely quite intrusive.
2024-09-06 14:00:30 -05:00
James Prestwood
3bc8b90c0e scan: don't survey on external scans
Since surveys end up making driver calls in the kernel its not
entirely known how they are implemented or how long they will
take. For this reason the survey will be skipped if getting the
results from an external scan.

Doing this also fixes a crash caused by external scans where the
scan request pointer is not checked and dereferenced:

0x00005ffa6a0376de in get_survey_done (user_data=0x5ffa783a3f90) at src/scan.c:2059
0x0000749646a29bbd in ?? () from /usr/lib/libell.so.0
0x0000749646a243cb in ?? () from /usr/lib/libell.so.0
0x0000749646a24655 in l_main_iterate () from /usr/lib/libell.so.0
0x0000749646a24ace in l_main_run () from /usr/lib/libell.so.0
0x0000749646a263a4 in l_main_run_with_signal () from /usr/lib/libell.so.0
0x00005ffa6a00d642 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:614

Reported-by: Daniel Bond <danielbondno@gmail.com>
2024-09-06 14:00:07 -05:00
James Prestwood
f6cfcb8ca2 dpp: use peer_addr for pkex exchange request
This was hard coded to broadcast and missed in the initial changes
to support starting PKEX to a specific peer.
2024-09-06 13:59:29 -05:00
James Prestwood
163c2ebd37 netdev: fix potential command ID overwrite setting CQM threshold
With the introduction of affinities the CQM threshold can be toggled
by a DBus call. There was no check if there was already a pending
call which would cause the command ID to be overwritten and lose any
potential to cancel it, e.g. if netdev went down.
2024-09-04 22:24:42 -05:00
James Prestwood
154a29be05 netdev: fall back to RSSI polling if SET_CQM fails
Some drivers fail to set a CQM threshold and report not supported.
Its unclear exactly why but if this happens roaming is effectively
broken.

To work around this enable RSSI polling if -ENOTSUP is returned.
The polling callback has been changed to emit the HIGH/LOW signal
threshold events instead of just the RSSI level index, just as if
a CQM event came from the kernel.
2024-09-04 22:24:18 -05:00
James Prestwood
23cf6107c6 monitor: fix build with INGRESS/EGRESS definitions
These new values are undefined on older kernels (e.g. 5.15)
2024-09-04 22:07:33 -05:00
James Prestwood
c66438e34f auto-t: add tests for Affinities behavior 2024-09-03 10:24:33 -05:00
James Prestwood
c778ddf0c2 auto-t: add affinities property for station, and extended_service_set 2024-09-03 10:24:28 -05:00
James Prestwood
2ad9561069 station: Use Affinities property to change roaming threshold
When the affinity is set to the current BSS lower the roaming
threshold to loosly lock IWD to the current BSS. The lower
threshold is automatically removed upon roaming/disconnection
since the affinity array is also cleared out.
2024-09-03 10:24:15 -05:00
James Prestwood
f4ec1ee509 station: add Affinities DBus property
This property will hold an array of object paths for
BasicServiceSet (BSS) objects. For the purpose of this patch
only the setter/getter and client watch is implemented. The
purpose of this array is to guide or loosely lock IWD to certain
BSS's provided that some external client has more information
about the environment than what IWD takes into account for its
roaming decisions.

For the time being, the array is limited to only the connected
BSS path, and any roams or disconnects will clear the array.

The intended use case for this is if the device is stationary
an external client could reduce the likelihood of roaming by
setting the affinity to the current BSS.
2024-09-03 10:19:02 -05:00
James Prestwood
b98bc30c23 dbus: add PermissionDenied DBus error 2024-09-03 10:18:56 -05:00
James Prestwood
4c3cbdc8d3 doc: Document station Affinities property
This documents new DBus property that expose a bit more control to
how IWD roams.

Setting the affinity on the connected BSS effectively "locks" IWD to
that BSS (except at critical RSSI levels, explained below). This can
be useful for clients that have access to more information about the
environment than IWD. For example, if a client is stationary there
is likely no point in trying to roam until it has moved elsewhere.

A new main.conf option would also be added:

[General].CriticalRoamThreshold

This would be the new roam threshold set if the currently connected
BSS is in the Affinities list. If the RSSI continues to drop below
this level IWD will still attempt to roam.
2024-09-03 10:18:50 -05:00
James Prestwood
61cba6bd28 station: check for roam timeout before rearming
A user reported a crash which was due to the roam trigger timeout
being overwritten, followed by a disconnect. Post-disconnect the
timer would fire and result in a crash. Its not clear exactly where
the overwrite was happening but upon code inspection it could
happen in the following scenario:

1. Beacon loss event, start roam timeout
2. Signal low event, no check if timeout is running and the timeout
   gets overwritten.

The reported crash actually didn't appear to be from the above
scenario but something else, so this logic is being hardened and
improved

Now if a roam timeout already exists and trying to be rearmed IWD
will check the time remaining on the current timer and either keep
the active timer or reschedule it to the lesser of the two values
(current or new rearm time). This will avoid cases such as a long
roam timer being active (e.g. 60 seconds) followed by a beacon or
packet loss event which should trigger a more agressive roam
schedule.
2024-09-03 10:16:25 -05:00
James Prestwood
574b0d80dc station: don't allow FT-over-Air without offchannel support
If CMD_REMAIN_ON_CHANNEL isn't supported, don't allow FT-over-Air
2024-09-03 10:08:05 -05:00
James Prestwood
0c228f4465 wiphy: add flag for supporting remain on channel 2024-09-03 10:07:55 -05:00
Marcel Holtmann
1ac3915641 Release 2.20 2024-08-29 10:41:03 +02:00
James Prestwood
e9ac7ab378 netdev: add critical signal threshold level
This adds a secondary set of signal thresholds. The purpose of these
are to provide more flexibility in how IWD roams. The critical
threshold is intended to be temporary and is automatically reset
upon any connection changes: disconnects, roams, or new connections.
2024-08-27 21:41:17 -05:00
James Prestwood
7ba5b0f924 netdev: store signal threshold in netdev object, not globally
This prepares for the ability to toggle between two signal
thresholds in netdev. Since each netdev may not need/want the
same threshold store it in the netdev object rather than globally.
2024-08-27 21:40:29 -05:00
James Prestwood
54b6330845 netdev: define netdev settings in netdev.h
Following knownnetworks, this moves the settings into a header file
which is easier to maintain/read.
2024-08-27 21:40:05 -05:00
James Prestwood
b5aff74e3b dpp: scale PKEX timeout by the number of frequencies used
If the number of frequencies used is very small reduce the timeout
to avoid waiting for extended periods of time.
2024-08-27 21:25:21 -05:00
James Prestwood
294426b450 dpp: allow PKEX configurators to run without multicast RX support
Since IWD enrollees can send unicast frames, a PKEX configurator could
still run without multicast support. Using this combination basically
allows any driver to utilize DPP/PKEX assuming the MAC address can
be communicated using some out of band mechanism.
2024-08-27 21:25:15 -05:00
James Prestwood
4482b8dc24 dpp: add Address/Frequency as parameters to PKEX enrollees
The DPP spec allows for obtaining frequency and MAC addresses up
to the implementation. IWD already takes advantage of this by
first scanning for nearby APs and using only those frequencies.
For further optimization an enrollee may be able to determine the
configurators frequency and MAC ahead of time which would make
finding the configurator much faster.
2024-08-27 21:24:48 -05:00
James Prestwood
bf2441e311 dpp: factor out key derivation and starting PKEX into functions
This will make things a bit easier in future patches, and reduces
some of the length/complexity of these functions.
2024-08-27 21:24:33 -05:00
James Prestwood
95a9e052de scan: remove legacy "Ghz" band modifier settings 2024-08-27 21:23:46 -05:00
James Prestwood
5c7777ff0f manager: deprecate UseDefaultInterface 2024-08-27 21:22:54 -05:00
James Prestwood
d223f49fbc doc: deprecate UseDefaultInterface in docs 2024-08-27 21:22:49 -05:00
Denis Kenzior
e5c0e18751 monitor: Print rmnet flags 2024-08-23 12:30:57 -05:00
Denis Kenzior
5f74ed75e7 nl80211util: Add builder for CMD_EXTERNAL_AUTH
This is for sending status from the STA to the driver
2024-08-23 11:18:15 -05:00
Denis Kenzior
17fbab110c nl80211util: support attributes in CMD_EXTERNAL_AUTH 2024-08-23 11:18:10 -05:00
Denis Kenzior
02ec70e290 monitor: Don't skip genl control Done,Error messages 2024-08-23 11:17:30 -05:00
Denis Kenzior
5118f08d79 monitor: Don't dump survey results with noscan
Survey is used after each scan, creating quite a bit of spam.  Silence
survey results if noscan is set.
2024-08-23 11:17:26 -05:00
Denis Kenzior
e565b75032 defs: Add defs.h to hold certain global definitions
This will help to get rid of magic number use throughout the project.
The definitions should be limited to global magic numbers that are used
throughout the project, for example SSID length, MAC address length,
etc.
2024-08-23 11:17:20 -05:00
James Prestwood
db9c0480ef station: emit property changed for ConnectedAccessPoint
This was missed in a prior patch set. When station is connecting
or disconnecting ConnectedAccessPoint property change should be
emitted.
2024-08-23 11:09:59 -05:00
Marcel Holtmann
10f5bc9be7 build: Require at least version 0.68 when building with external ELL 2024-08-22 17:13:48 +02:00
James Prestwood
548ef00291 auto-t: Add test for BasicServiceSets 2024-08-19 11:43:30 -05:00
James Prestwood
93806cd522 auto-t: Add ExtendedServiceSet property 2024-08-19 11:43:27 -05:00
James Prestwood
1a3a035404 network: add back network_bss_list_clear
Rename network_bss_update_start back to network_bss_list_clear, since
this is what its now doing again.
2024-08-19 11:43:24 -05:00
James Prestwood
6d94599977 network: remove BasicServiceSet DBus registration code
This was moved into station.
2024-08-19 11:43:24 -05:00
James Prestwood
c639bf0b19 station: move BasicServiceSet DBus management into station
Due to an unnoticed bug after adding the BasicServiceSet object into
network, it became clear that since station already owns the scan_bss
objects it makes sense for it to manage the associated DBus objects
as well. This way network doesn't have to jump through hoops to
determine if the scan_bss object was remove, added, or updated. It
can just manage its list as it did prior.

From the station side this makes things very easy. When scan results
come in we either update or add a new DBus object. And any time a
scan_bss is freed we remove the DBus object.
2024-08-19 11:43:24 -05:00
James Prestwood
514e483bc3 network: add __network_path_append_bss
To reduce code duplication and prepare for moving the BSS interface
to station, add a new API so station can create a BSS path without
a network object directly.
2024-08-19 11:43:24 -05:00
Denis Kenzior
7604762013 eapol: Fix bogus warning
src/eapol.c:1041:9: error: ‘buf’ may be used uninitialized [-Werror=maybe-uninitialized]
 1041 |         l_put_be16(0, &frame->header.packet_len);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This warning is bogus since the buffer is initialized through use of
eapol_frame members.  EAPoL-Start is a very simple frame.
2024-08-19 11:43:24 -05:00
James Prestwood
f81855349a auto-t: add SAE-H2E test for setting the default ECC group 2024-08-12 16:19:16 -05:00
James Prestwood
1455988efb sae: support default group for H2E
This was seemingly trivial at face value but doing so ended up
pointing out a bug with how group_retry is set when forcing
the default group. Since group_retry is initialized to -1 the
increment in the force_default_group block results in it being
set to zero, which is actually group 20, not 19. This did not
matter for hunt and peck, but H2E actually uses the retry value
to index its pre-generated points which then breaks SAE if
forcing the default group with H2E.

To handle H2E and force_default_group, the group selection
logic will always begin iterating the group array regardless of
SAE type.
2024-08-12 13:13:00 -05:00
James Prestwood
d2f14b2951 client: add station command "get-bsses"
This command will get the BasicServiceSet list for a given network.
If no network is supplied, its assumed to be the current network.
2024-08-12 12:10:58 -05:00
James Prestwood
73c79dbd41 client: refactor cmd_connect() and add find_network()
This will do all the lookup/searching needed to find a network
proxy object.
2024-08-12 12:10:58 -05:00
James Prestwood
0d7ff8ebd9 client: add BasicServiceSet interface 2024-08-12 12:10:58 -05:00
James Prestwood
05166d0999 client: Add BasicServiceSets property to network
The property itself is an array of paths, but this is difficult
to fit nicely within a terminal. Instead just display the count
of BSS's. Displaying a detailed list of BSS's will be done via
a separate command.
2024-08-12 12:10:58 -05:00
James Prestwood
0e3322b5da client: add net.connman.iwd.BasicServiceSet definition 2024-08-12 12:10:55 -05:00
James Prestwood
a7d8b9a068 client: separate property header and values into two functions
There are certain cases where we may not want to display the entire
header for a given set of properties. For example displaying a list
of proxy interfaces. Add finer control by separating out the header
and the prop/value display into two functions.
2024-08-12 12:10:50 -05:00
James Prestwood
b31e298df4 doc: document BasicServiceSet API 2024-08-12 12:10:47 -05:00
James Prestwood
a73b877c5b station: add ConnectedAccessPoint property
This property is a path that corresponds to a BasicServiceSet
object, the one the station is currently connected to.
2024-08-12 12:10:44 -05:00
James Prestwood
68e1d055dd network: remove network_bss_list_clear 2024-08-12 12:10:40 -05:00
James Prestwood
aca92df19b network: add ExtendedServiceSet DBus property
This contains a list of all BasicServiceSet objects (paths) that
exist for a network.
2024-08-12 12:10:28 -05:00
James Prestwood
560ad581ad station: use network_bss_{start,stop}_update
This will tell network the BSS list is being updated and it can
act accordingly as far as the BSS DBus registrations/unregistration.

In addition any scan_bss object needing to be freed has to wait
until after network_bss_stop_update() because network has to be able
to iterate its old list and unregister any BSS's that were not seen
in the scan results. This is done by pushing each BSS needing to be
freed into a queue, then destroying them after the BSS's are all
added.
2024-08-12 12:10:10 -05:00
James Prestwood
fe2a91ae11 network: Add BasicServiceSet object
This adds a new DBus object/interface for tracking BSS's for
a given network. Since scanning replaces scan_bss objects some
new APIs were added to avoid tearing down the associated DBus
object for each BSS.

network_bss_start_update() should be called before any new BSS's
are added to the network object. This will keep track of the old
list and create a new network->bss_list where more entries can
be added. This is effectively replacing network_bss_list_clear,
except it keeps the old list around until...

network_bss_stop_update() is called when all BSS's have been
added to the network object. This will then iterate the old list
and lookup if any BSS DBus objects need to be destroyed. Once
completed the old list is destroyed.
2024-08-12 12:01:57 -05:00
James Prestwood
cd1507620f dbus: Add net.connman.iwd.BasicServiceSet interface 2024-08-12 12:01:34 -05:00
Denis Kenzior
7ee7848a96 netdev: Simplify FILS handling in netdev_connect_common 2024-08-05 09:07:02 -05:00
Denis Kenzior
be7b19d587 fils: Ensure capability checks are consistent
iwd supports FILS only on softmac drivers.  Ensure the capability check
is consistent between wiphy and netdev, both the softmac and the
relevant EXT_FEATURE bit must be checked.

CMD_EXTERNAL_AUTH could potentially be used for FILS for FullMAC cards,
but no hardware supporting this has been identified yet.
2024-08-05 09:06:54 -05:00
Denis Kenzior
16f5bbc20a netdev: Create owe_sm for fullmac connections
Somehow this ability was lost in the refactoring.  OWE was intended to
be used on fullmac cards, but the state machine is only actually created
if the connection type ends up being softmac.

Fixes: 8b6ad5d3b9ec ("owe: netdev: refactor to remove OWE as an auth-proto")
2024-08-05 09:06:43 -05:00
Denis Kenzior
8a27cff8c0 ie: Add IE_AKM_IS_OWE
Similarly to IE_AKM_IS_SAE, IE_AKM_IS_FILS, etc
2024-08-05 09:06:39 -05:00
Denis Kenzior
d43f05224d wiphy: Fix use of wiphy_has_feature
Features with the _EXT_ in the name must be queried using the
wiphy_has_ext_feature method.

Fixes: bc7b12d1a4a7 ("wiphy: handle FILS AKMs")
2024-08-05 09:06:31 -05:00
Denis Kenzior
96492483ee monitor: Mask flags from attribute identifier
Certain flags (for example, NLA_F_NESTED) are ORed with the netlink
attribute type identifier prior to being sent on the wire.  Such flags
need to be masked off and not taken into consideration when attribute
type is being compared against known values.
2024-08-05 09:06:25 -05:00
Denis Kenzior
194d8a3052 monitor: Decode RMNet Mux Identifier 2024-08-05 09:06:20 -05:00
James Prestwood
d500a44ff3 station: improve zero oper class neighbor report workaround
The workaround for Cisco APs reporting an operating class of zero
is still a bug that remains in Cisco equipment. This is made even
worse with the introduction of 6GHz where the channel numbers
overlap with both 2.4 and 5GHz bands. This makes it impossible to
definitively choose a frequency given only a channel number.

To improve this workaround and cover the 6GHz band we can calculate
a frequency for each band and see what is successful. Then append
each frequency we get to the list. This will result in more
frequencies scanned, but this tradeoff is better than potentially
avoiding a roam to 6GHz or high order 5ghz channel numbers.
2024-08-05 09:05:49 -05:00
Denis Kenzior
faa6a392e4 monitor: Update to the new ell l_netlink_send API 2024-07-26 17:37:29 -05:00
Denis Kenzior
e33fa63243 netdev: Update to the new l_netlink_send API 2024-07-26 17:37:29 -05:00
Denis Kenzior
d7f669dd7c wired: Update to the new l_netlink_send API 2024-07-26 17:37:29 -05:00
Denis Kenzior
993e48cab2 qemu: Remove unsupported command line arguments
[denkenz@archdev ~]$ qemu-system-x86_64 --version
QEMU emulator version 9.0.1
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers

QEMU now seems to complain that 'no-hpet' and 'no-acpi' command line
arguments are unrecognized.
2024-07-26 10:06:13 -05:00
Denis Kenzior
9762c61b4d monitor: Use genl APIs instead of open coding
l_genl class has nice ways of discovering and requesting families.  The
genl functionality has been added after the iwmon skeleton was created,
but it is now time to migrate to using these APIs.
2024-07-26 10:04:05 -05:00
James Prestwood
d8803b309d monitor: fix the CQM RSSI threshold attribute
This attribute is actually an array of signed 32 bit integers and it
was being treated as a single integer. This would work until more
than one threshold was set, then it would fail to parse it.
2024-07-26 09:52:25 -05:00
James Prestwood
f9a55e3728 auto-t: fix several DPP tests after station state changes
After the station state changes in DPP setting autoconnect=True was
causing DPP to stop prior to being able to scan for the network.
Instead we can start autoconnect earlier so we aren't toggling the
property while DPP is running.
2024-07-24 15:26:57 -05:00
James Prestwood
a63fd6abb9 auto-t: add DPP tests for state change checks 2024-07-24 15:26:55 -05:00
James Prestwood
eff2a2afcf dpp: explicitly disconnect station if enrollee is started
Prior to now the DPP state was required to be disconnected before
DPP would start. This is inconvenient for the user since it requires
extra state checking and/or DBus method calls. Instead model this
case like WSC and issue a disconnect to station if DPP is requested
to start.

The other conditions on stopping DPP are also preserved and no
changes to the configurator role have been made, i.e. being
disconnected while configuring still stops DPP. Similarly any
connection made during enrolling will stop DPP.

It should also be noted that station's autoconfigure setting is also
preserved and set back to its original value upon DPP completing.
2024-07-24 15:25:31 -05:00
James Prestwood
5cdad6ab86 station: add station_get_autoconnect
Gets the current autoconenct setting. This is not the current
autoconnect state. Will be used in DPP to reset station's autoconnect
setting back to what it was prior to DPP, in case of failure.
2024-07-24 15:25:28 -05:00
James Prestwood
30ca00d2c4 dpp: factor out PKEX/DPP start prep into function
In order to slightly rework the DPP state machine to handle
automatically disconnecting (for enrollees) functions need to be
created that isolate everything needed to start DPP/PKEX in case
a disconnect needs to be done first.
2024-07-24 15:25:25 -05:00
James Prestwood
fbf8ed4140 auto-t: don't print valgrind log if there was no error
If valgrind didn't report any issues, don't dump the logs. This
makes the test run a lot easier to look at without having to scroll
through pages of valgrind logs that provide no value.
2024-07-24 09:14:09 -05:00
James Prestwood
64d68b4f08 scan: fix invalid read when canceling an ongoing scan
When the survey code was added it neglected to add the same
cancelation logic that existed for the GET_SCAN call, i.e. if
a scan was canceled and there was a pending GET_SURVEY to the
kernel that needs to be canceled, and the request cleaned up.

Fixes: 35808debae ("scan: use GET_SURVEY for SNR calculation in ranking")
2024-07-24 09:12:42 -05:00
Yuki Sireneva
91f7253ae1 client: use display_table_row for IPv6 in station
IPv6 address entry was not updated to use display_table_row which led to
a shifted line in table, as shown below:

    $ iwctl station wlan0 show | head | sed 's| |.|g'
    .................................Station:.wlan0................................
    --------------------------------------------------------------------------------
    ..Settable..Property..............Value..........................................
    --------------------------------------------------------------------------------
    ............Scanning..............no...............................................
    ............State.................connected........................................
    ............Connected.network.....Clannad.Legacy...................................
    ............IPv4.address..........192.168.1.12.....................................
    ............IPv6.address........fdc3:541d:864f:0:96db:c9ff:fe36:b15............
    ............ConnectedBss..........cc:d8:43:77:91:0e................................

This patch aligns IPv6 address line with other lines in the table.

Fixes: 35dd2c08219a (client: update station to use display_table_row, 2022-07-07)
2024-07-23 18:52:51 -05:00
James Prestwood
06c8080664 auto-t: a few random autotest fixes
testEncryptedProfiles:
 - This would occationally fail because the test is expecting
   to explicitly connect but after the first failed connection
   autoconnect takes over and its a race to connect.
testPSK-roam:
 - Several rules were not being cleaned up which could cause
   tests afterwards to fail
 - The AP roam test started failing randomly because of the SNR
   ranking changes. It appears that with hwsim _sometimes_ the
   SNR is able to be determined which can effect the ranking. This
   test assumed the two BSS's would be the same ranking but the
   SNR sometimes causes this to not be true.
2024-07-18 16:08:46 -05:00
James Prestwood
b7da34a5d2 auto-t: Add deauth during the 4-way handshake test
This test will fail with current upstream as IWD hangs when the
deauthenticate event arrives. Once this is fixed the test should
pass.
2024-07-18 16:08:43 -05:00
James Prestwood
a972b77dc2 auto-t: add reason/test arguments to hostapd deauthenticate
The reason code is obvious, but the test argument is actually a
toggle to send the frame encrypted or unencrypted.
2024-07-18 16:08:40 -05:00
James Prestwood
d27de1b111 auto-t: add clear_events() to IWD class
The wait_for_event() function allows past events to cause this
function to return immediately. This behavior is known, and
relied on for some tests. But in some cases you want to only
handle _new_ events, so we need a way to clear out prior events.
2024-07-18 16:08:36 -05:00
James Prestwood
d2cda84383 station: add handshake-started debug event 2024-07-18 16:08:32 -05:00
James Prestwood
af1b017003 eapol: move HANDSHAKE_STARTED_EVENT to eapol_start()
This event is not used anywhere and can be leveraged in autotesting.
Move the event to eapol_start() so it gets called unconditionally
when the 4-way handshake is started.
2024-07-18 16:08:17 -05:00
James Prestwood
556f90ec28 netdev: handle disconnect event during a connection
If a disconnect arrives at any point during the 4-way handshake or
key setting this would result in netdev sending a disconnect event
to station. If this is a reassociation this case is unhandled in
station and causes a hang as it expects any connection failure to
be handled via the reassociation callback, not a random disconnect
event.

To handle this case we can utilize netdev_disconnected() along with
the new NETDEV_RESULT_DISCONNECTED result to ensure the connect
callback gets called if it exists (indicating a pending connection)

Below are logs showing the "Unexpected disconnect event" which
prevents IWD from cleaning up its state and ultimately results in a
hang:

Jul 16 18:16:13: src/station.c:station_transition_reassociate()
Jul 16 18:16:13: event: state, old: connected, new: roaming
Jul 16 18:16:13: src/wiphy.c:wiphy_radio_work_done() Work item 65 done
Jul 16 18:16:13: src/wiphy.c:wiphy_radio_work_next() Starting work item 66
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
Jul 16 18:16:13: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Deauthenticate(39)
Jul 16 18:16:13: src/netdev.c:netdev_deauthenticate_event()
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification New Station(19)
Jul 16 18:16:13: src/station.c:station_netdev_event() Associating
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Authenticate(37)
Jul 16 18:16:13: src/netdev.c:netdev_authenticate_event()
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Associate(38)
Jul 16 18:16:13: src/netdev.c:netdev_associate_event()
Jul 16 18:16:13: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Connect(46)
Jul 16 18:16:13: src/netdev.c:netdev_connect_event()
Jul 16 18:16:13: src/netdev.c:netdev_connect_event() aborting and ignore_connect_event not set, proceed
Jul 16 18:16:13: src/netdev.c:netdev_connect_event() expect_connect_failure not set, proceed
Jul 16 18:16:13: src/netdev.c:parse_request_ies()
Jul 16 18:16:13: src/netdev.c:netdev_connect_event() Request / Response IEs parsed
Jul 16 18:16:13: src/netdev.c:netdev_get_oci()
Jul 16 18:16:13: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:13: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:13: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:13: src/netdev.c:netdev_get_oci_cb() Obtained OCI: freq: 5220, width: 3, center1: 5210, center2: 0
Jul 16 18:16:13: src/eapol.c:eapol_start()
Jul 16 18:16:13: src/netdev.c:netdev_unicast_notify() Unicast notification Control Port Frame(129)
Jul 16 18:16:13: src/netdev.c:netdev_control_port_frame_event()
Jul 16 18:16:13: src/eapol.c:eapol_handle_ptk_1_of_4() ifindex=6
Jul 16 18:16:13: src/netdev.c:netdev_mlme_notify() MLME notification Control Port TX Status(139)
Jul 16 18:16:14: src/netdev.c:netdev_mlme_notify() MLME notification Notify CQM(64)
Jul 16 18:16:14: src/netdev.c:netdev_cqm_event() Signal change event (above=1 signal=-60)
Jul 16 18:16:17: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:17: src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
Jul 16 18:16:17: src/netdev.c:netdev_mlme_notify() MLME notification Deauthenticate(39)
Jul 16 18:16:17: src/netdev.c:netdev_deauthenticate_event()
Jul 16 18:16:17: src/netdev.c:netdev_mlme_notify() MLME notification Disconnect(48)
Jul 16 18:16:17: src/netdev.c:netdev_disconnect_event()
Jul 16 18:16:17: Received Deauthentication event, reason: 15, from_ap: true
Jul 16 18:16:17: src/wiphy.c:wiphy_radio_work_done() Work item 66 done
Jul 16 18:16:17: src/station.c:station_disconnect_event() 6
Jul 16 18:16:17: Unexpected disconnect event
Jul 16 18:16:17: src/netdev.c:netdev_link_notify() event 16 on ifindex 6
Jul 16 18:16:17: src/wiphy.c:wiphy_reg_notify() Notification of command Reg Change(36)
Jul 16 18:16:17: src/wiphy.c:wiphy_update_reg_domain() New reg domain country code for (global) is XX
2024-07-18 16:07:41 -05:00
James Prestwood
22f238706c station: update logic for handshake failure
After adding the NETDEV_RESULT_DISCONNECTED enum, handshake failures
initiated by the AP come in via this result so the existing logic
to call network_connect_failed() was broken. We could still get a
handshake failure generated internally, so that has been preserved
(via NETDEV_RESULT_HANDSHAKE_FAILED) but a check for a 4-way
handshake timeout reason code was also added.
2024-07-18 16:06:41 -05:00
James Prestwood
906afefbf3 station: handle NETDEV_RESULT_DISCONNECTED
This new event is sent during a connection if netdev recieves a
disconnect event. This patch cleans up station to handle this
case and leave the existing NETDEV_EVENT_DISCONNECTED_BY_{AP,SME}
handling only for CONNECTED, NETCONFIG, and FW_ROAMING states.
2024-07-18 16:05:37 -05:00
James Prestwood
38c36ff145 netdev: add NETDEV_RESULT_DISCONNECTED
This new result is meant to handle cases where a disconnect
event (deauth/disassoc) was received during an ongoing connection.
Whether that's during authentication, association, the 4-way
handshake, or key setting.
2024-07-18 16:05:14 -05:00
James Prestwood
9ea0117dc4 station: print unknown channel number in neighbor report
If the channel number resulted in a failure to parse the neighbor
report entry, print it for debugging.
2024-07-18 16:05:01 -05:00
Kasper Kantz
4f81953338 p2putil: remove static from const strlen
src/p2putil.c: In function 'p2p_get_random_string':
 src/p2putil.c:2641:37: error: initializer element is not constant     2641 |
        static const int set_size = strlen(CHARSET);         |
                     ^~~~~~
2024-07-12 16:24:00 -05:00
Steve Schrock
ffc6d6325d main: update usage with logger option 2024-07-12 11:58:51 -05:00
Steve Schrock
6d46698494 main: set the identity in the logger
This causes "iwd" to be output in each message sent to syslog to help
quickly identify iwd messages.
2024-07-11 17:13:43 -05:00
Marcel Holtmann
b54dcafa80 Release 2.19 2024-07-08 22:12:42 +02:00
Marcel Holtmann
ac0f13798b build: Add test-nl80211util binary to ignore list 2024-07-08 22:12:20 +02:00
Marcel Holtmann
51771694cd build: Require at least version 0.67 when building with external ELL 2024-07-08 22:11:24 +02:00
James Prestwood
9232991e25 auto-t: add test for a deauth coming in during an FT-roam 2024-06-26 09:38:06 -05:00
James Prestwood
71dc347582 station: add debug event prior to sending an FT-auth frame 2024-06-26 09:38:06 -05:00
James Prestwood
31b18a8c8b auto-t: add test for deauth after authentication
This code path is not exercised in the autotest but commonly does
happen in the real world. There is no associated bug with this, but
its helpful to have this event triggered in case something got
introduced in the future.
2024-06-26 09:38:06 -05:00
James Prestwood
d92e4c5663 station: add auth/assoc debug events
These will be useful to trigger behavior around authentication and
association.
2024-06-26 09:38:06 -05:00
James Prestwood
300f0ddac5 netdev: reuse NETDEV_EVENT_{AUTHENTICATING,ASSOCIATING}
The authenticating event was not used anymore and the associating
event use was questionable (after the CMD_CONNECT callback).

No other modules actually utilize these events but they are useful
for autotests. Move these events around to map 1:1 when the kernel
sends the auth/assoc events.
2024-06-26 09:38:06 -05:00
James Prestwood
77cf621f15 nl80211util: use nl80211_parse_attrs/nested for get_key_seq
This really reduces the number of checks needed and overall function
length by using the helper APIs.
2024-06-26 09:38:06 -05:00
James Prestwood
5c824cc24e netdev: use nl80211_parse_attrs for deauth event
Especially for parsing a single attribute, nl80211_parse_attrs
makes the most sense to use here.
2024-06-26 09:38:06 -05:00
James Prestwood
3fd5250c0d station: refactor the printing of scan results, print SNR/load
There are a few values which are nice to see in debug logs. Namely
the BSS load and SNR. Both of these values may not be available
either due to the AP or local hardware limiations. Rather than print
dummy values for these refactor the print so append the values only
if they are set in the scan result.
2024-06-20 10:51:00 -05:00
James Prestwood
8de70b1952 scan: add flag if BSS load was advertised
For ranking purposes the utilization was defaulted to a valid (127)
which would not change the rank if that IE was not found in the
scan results. Historically this was printed (debug) as part of the
scan results but that was removed as it was somewhat confusing. i.e.
did the AP _really_ have a utilization of 127? or was the IE not
found?

Since it is useful to see the BSS load if that is advertised add a
flag to the scan_bss struct to indicate if the IE was present which
can be checked.
2024-06-20 10:51:00 -05:00
James Prestwood
35808debae scan: use GET_SURVEY for SNR calculation in ranking
This issues a GET_SURVEY dump after scan results are available and
populates the survey information within the scan results. Currently
the only value obtained is the noise for a given frequency but the
survey results structure was created if in the future more values
need to be added.

From the noise, the SNR can be calculated. This is then used in the
ranking calculation to help lower BSS ranks that are on high noise
channels.
2024-06-20 10:51:00 -05:00
James Prestwood
685d105739 unit: add simple test for nl80211util 2024-06-20 10:51:00 -05:00
James Prestwood
43d5e89fac scan: fixed flush flag parsing
Parsing the flush flag for external scans was not done correctly
as it was not parsing the ATTR_SCAN_FLAGS but instead the flag
bitmap. Fix this by parsing the flags attribute, then checking if
the bit is set.
2024-06-20 10:51:00 -05:00
James Prestwood
88a71eca72 nl80211util: add ATTR_SCAN_FLAGS 2024-06-20 10:51:00 -05:00
James Prestwood
b4983fdcae nl80211util: add nl80211_parse_nested
Add a nested attribute parser. For the first supported attribute
add NL80211_ATTR_SURVEY_INFO.

This allows parsing of nested attributes in the same convenient
way as nl80211_parse_attrs but allows for support of any level of
nested attributes provided that a handler is added for each.
2024-06-20 10:51:00 -05:00
James Prestwood
16a05316b2 nl80211util: refactor nl80211_parse_attrs for nested variant
To prep for adding a _nested() variant of this function refactor
this to act on an l_genl_attr object rather than the message itself.
In addition a handler specific to the attribute being parsed is
now passed in, with the current "handler_for_type" being renamed to
"handler_for_nl80211" that corresponds to root level attributes.
2024-06-20 10:51:00 -05:00
James Prestwood
1dda441b85 nl80211util: add ATTR_SURVEY_INFO to parse_attrs 2024-06-20 10:51:00 -05:00
James Prestwood
5cf826c73a netdev: downgrade L_WARN_ON for ensure_eapol_registered
This warning is guaranteed to happen for SAE networks where there are
multiple netdev_authenticate_events. This should just be a check so
we don't register eapol twice, not a warning.
2024-06-20 10:51:00 -05:00
Marcel Holtmann
9a5c64481e Release 2.18 2024-06-04 15:36:50 +02:00
Marcel Holtmann
6de09a5eba build: Require at least version 0.66 when building with external ELL 2024-06-03 20:33:31 +02:00
Laura Peeters
03645acf4f eap-tls: Allow tls_msg_len to be zero
EAP-TTLS Start packets are empty by default, but can still be sent with
the L flag set. When attempting to reassemble a message we should not
fail if the length of the message is 0, and just treat it as any other
unfragmented message with the L flag set.
2024-05-31 16:23:15 -05:00
Denis Kenzior
c1e2a6c44c build: Add notifylist.[ch] from ell 2024-05-31 15:45:11 -05:00
Denis Kenzior
b3e7b7539e watchlist: Remove unused APIs
watchlist_new and watchlist_free were never used.  Get rid of them.
2024-05-29 17:52:23 -05:00
James Prestwood
fdbbd8b383 unit: add test for band fallback
This test uses the same country/country3 values seen by an AP vendor
which causes issues with IWD. The alpha2 is ES (Spain) and the 3rd
byte is 4, indicating to use the E-4. The issue then comes when the
neighbor report claims the BSS is under operating class 3 which is
not part of E-4.

With the fallback implemented, this test will pass since it will
try and lookup only on ES (the EU table) which operating class 3 is
part of.
2024-05-14 10:30:48 -05:00
James Prestwood
70d1d71612 band: support band lookup fallback for buggy APs
Its been seen that some vendors incorrectly set the 3rd byte of the
country code which causes the band lookup to fail with the provided
operating class. This isn't compliant with the spec, but its been
seen out in the wild and it causes IWD to behave poorly, specifically
with roaming since it cannot parse neighbor reports. This then
requires IWD to do a full scan on each roam.

Instead of a hard rejection, IWD can instead attempt to determine
the band by ignoring that 3rd byte and only use the alpha2 string.
This makes IWD slightly less strict but at the advantage of not being
crippled when exposed to poor AP configurations.
2024-05-14 10:27:36 -05:00
James Prestwood
4bfc794a37 auto-t: remove default group SAE test for specific OUI
There are already tests for UseDefaultEccGroup and this test is
not longer valid as the static OUI list has been removed.
2024-05-14 10:26:17 -05:00
James Prestwood
8a1f8d1a9a ie: remove is_ie_default_sae_group_oui
This is no longer used and instead a generic option was added
rather than referencing a static OUI list.
2024-05-14 10:26:11 -05:00
James Prestwood
b05c1cafcd scan: remove force_default_sae_group from scan_bss
This was added to support a single buggy AP model that failed to
negotiate the SAE group correctly. This may still be a problem but
since then the [Network].UseDefaultEccGroup option has been added
which accomplishes the same thing.

Remove the special handling for this specific OUI and rely on the
user setting the new option if they have problems.
2024-05-14 10:25:46 -05:00
James Prestwood
3be01a83ab build: Create ell directory for ell/ell.h target
Both ell/shared and ell/internal targets first create the ell/
directory within IWD. This apparently was just luck that one of
these always finished first in parallel builds. On my system at
least when building using dpkg-buildpackage IWD fails to build
due to the ell/ directory missing. From the logs it appears that
both the shared/internal targets were started but didn't complete
(or at least create the directory) before the ell/ell.h target:

make[1]: Entering directory '/home/jprestwood/tmp/iwd'
/usr/bin/mkdir -p ell
/usr/bin/mkdir -p ell
echo -n > ell/ell.h
/usr/bin/mkdir -p src
/bin/bash: line 1: ell/ell.h: No such file or directory
make[1]: *** [Makefile:4028: ell/ell.h] Error 1

Creating the ell/ directory within the ell/ell.h target solve
the issue. For reference this is the configure command dpkg
is using:

./configure --build=x86_64-linux-gnu \
	--prefix=/usr \
	--includedir=/usr/include \
	--mandir=/usr/share/man \
	--infodir=/usr/share/info \
	--sysconfdir=/etc \
	--localstatedir=/var \
	--disable-option-checking \
	--disable-silent-rules \
	--libdir=/usr/lib/x86_64-linux-gnu \
	--runstatedir=/run \
	--disable-maintainer-mode \
	--disable-dependency-tracking \
	--enable-tools \
	--enable-dbus-policy
2024-05-14 10:24:09 -05:00
James Prestwood
26efca80d7 nlmon: parse/print neighbor reports
Adds an IE parser for neighbor report elements
2024-05-09 10:23:45 -05:00
John Brandt
5fb3ac5937 eapol: include IGTK in 4-way handshake as AP
When SAE with MFP is being used, include the IGTK in message 3 of the
4-way handshake.
2024-05-07 11:19:51 -05:00
John Brandt
9274f70fec handshake: add functions to save and set IGTK
To add MFP support in the AP mode, add utility functions to save the
IGTK and to add the IGTK to handshake messages.
2024-05-07 11:15:25 -05:00
John Brandt
78bdb26296 eapol: encrypt key data for AKM-defined ciphers
Support encrypting key data when the cipher is AKM-defined. This is
needed to support SAE in AP mode.
2024-05-07 11:03:45 -05:00
John Brandt
3132e9f595 eapol: support PTK derivation with SHA256
Support PTK derivation in case the negotiated AKM requires SHA256. This
is needed to support SAE in AP mode.
2024-05-07 10:52:20 -05:00
John Brandt
b9e4dfbd40 sae: support reception of Confirm frame by AP
Experimental AP-mode support for receiving a Confirm frame when in the
COMMITTED state. The AP will reply with a Confirm frame.

Note that when acting as an AP, on reception of a Commit frame, the AP
only replies with a Commit frame. The protocols allows to also already
send the Confirm frame, but older clients may not support simultaneously
receiving a Commit and Confirm frame.
2024-05-07 10:50:39 -05:00
John Brandt
2e80a09184 sae: refactor and add function sae_calculate_keys
Refactor code by moving code to the new function sae_calculate_keys.
This will make it easier in the next commits to add SAE support for AP
mode.
2024-05-07 10:50:39 -05:00
John Brandt
49cddea10b unit: fix SAE unit tests
Don't mark either client as being the authenticator. In the current unit
tests, both instances act as clients to test functionality. This ensures
the unit does not show an error during the following commits where SAE
for AP mode is added.
2024-05-07 10:50:39 -05:00
Marcel Holtmann
be3f6a2ca0 udev: Add module for checking interface renaming actions 2024-04-16 14:57:57 +02:00
James Prestwood
88d3261bc2 unit: fix test-band with new rate estimation returns
-ENETUNREACH is the correct return to check as this indicates either
the RSSI was too low or the local capabilities were not compatible.
2024-04-15 16:51:54 -05:00
James Prestwood
e5816b024f band: return -ENETUNREACH for HE rate estimation
This was overlooked in a prior patch and causes warnings to be
printed when the RSSI is too low to estimate an HE data rate or
due to incompatible local capabilities (e.g. MCS support).

Similar to the other estimations, return -ENETUNREACH if the IE
was valid but incompatible.
2024-04-15 16:51:54 -05:00
James Prestwood
9cdc726dc1 wiphy: handle -ENETUNREACH for rate estimation
If the RSSI is too low or the local capabilities were not
compatible to estimate the rate don't warn but instead treat
this the same as -ENOTSUP and drop down to the next capability
set.
2024-04-15 16:51:54 -05:00
James Prestwood
e196cb1178 wiphy: include MAC of BSS with invalid HE capabilities
The prior print was not very descriptive, and now will log the
MAC of the offending BSS.
2024-04-15 16:51:54 -05:00
Marcel Holtmann
468cecdbca Release 2.17 2024-03-29 00:26:29 +01:00
Marcel Holtmann
546dea11b6 build: Require at least version 0.64 when building with external ELL 2024-03-29 00:03:13 +01:00
Ed Smith
da13aab419 Register EAPOL frame listeners earlier
If we register the main EAPOL frame listener as late as the associate
event, it may not observe ptk_1_of_4. This defeats handling for early
messages in eapol_rx_packet, which only sees messages once it has been
registered.

If we move registration to the authenticate event, then the EAPOL
frame listeners should observe all messages, without any possible
races. Note that the messages are not actually processed until
eapol_start() is called, and we haven't moved that call site. All
that's changing here is how early EAPOL messages can be observed.
2024-03-28 17:41:07 -05:00
James Prestwood
ccd702f7da netdev: use CMD_DEAUTHENTICATE when needed on disconnect
netdev_disconnect() was unconditionally sending CMD_DISCONNECT which
is not the right behavior when IWD has not associated. This means
that if a connection was started then immediately canceled with
the Disconnect() method the kernel would continue to authenticate.

Instead if IWD has not yet associated it should send a deauth
command which causes the kernel to correctly cleanup its state and
stop trying to authenticate.

Below are logs showing the behavior. Autoconnect is started followed
immediately by a DBus Disconnect call, yet the kernel continues
sending authenticate events.

event: state, old: autoconnect_quick, new: connecting (auto)
src/scan.c:scan_cancel() Trying to cancel scan id 1 for wdev 7d
src/wiphy.c:wiphy_radio_work_done() Work item 1 done
src/wiphy.c:wiphy_radio_work_next() Starting work item 2
src/netdev.c:netdev_mlme_notify() MLME notification New Station(19)
src/station.c:station_dbus_disconnect()
src/station.c:station_reset_connection_state() 85
src/station.c:station_roam_state_clear() 85
event: state, old: connecting (auto), new: disconnecting
src/wiphy.c:wiphy_radio_work_done() Work item 2 done
src/station.c:station_connect_cb() 85, result: 5
src/station.c:station_disconnect_cb() 85, success: 1
event: state, old: disconnecting, new: disconnected
src/netdev.c:netdev_mlme_notify() MLME notification Authenticate(37)
src/netdev.c:netdev_authenticate_event()
Unexpected connection related event -- is another supplicant running?
src/netdev.c:netdev_mlme_notify() MLME notification Authenticate(37)
src/netdev.c:netdev_authenticate_event()
Unexpected connection related event -- is another supplicant running?
src/netdev.c:netdev_mlme_notify() MLME notification Authenticate(37)
src/netdev.c:netdev_authenticate_event()
Unexpected connection related event -- is another supplicant running?
src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
src/netdev.c:netdev_mlme_notify() MLME notification Authenticate(37)
src/netdev.c:netdev_authenticate_event()
Unexpected connection related event -- is another supplicant running?
2024-03-28 17:16:37 -05:00
James Prestwood
6365c1f6de wiphy: add better handling for rate estimation errors
In most cases any failure here is likely just due to the AP not
supporting the feature, whether its HE/VHT/HE. This should result
in the estimation returning -ENOTSUP in which case we move down
the list. Any other non-zero return we will now warn to make it
clear the IEs did exist, but were not properly formatted.

All length check failures were changed to continue instead of
fail. This will now treat invalid lengths as if the IE did not
exist.

In addition HE specifically has an extra validation function which,
if failed, was bailing out of the estimation function entirely.
Instead this is now treated as if there was no HE capabilities and
the logic can move down to VHT, HT, or basic rates.
2024-03-28 10:21:08 -05:00
James Prestwood
2f2b5740da band: make HE/no-HT rate estimators return more descriptive
If the IEs were not provided return -ENOTSUP rather than -EINVAL
or -EBADMSG since this just means the AP doesn't support those
capabilities.
2024-03-28 10:20:53 -05:00
James Prestwood
6b94ab3889 iwmon: fix incorrect mask printing HE capabilities
This was changed from too large of a mask (0xff) in an earlier
commit but was masking 5 bits instead of 6.

Fixes: 121c2c5653 ("monitor: properly mask HE capabilities bitfield")
2024-03-15 08:46:56 -05:00
James Prestwood
6bedcb4622 client: fix two issues caught by static analysis
- va_end was not being called on an error condition
 - An uninitialized struct was being accessed if ioctl failed
2024-03-11 22:08:26 -05:00
James Prestwood
121c2c5653 monitor: properly mask HE capabilities bitfield
Caught by static analysis, the bitfield was incorrect and was masking
8 entries (0xff), not 5 (0x1f).
2024-03-11 22:08:19 -05:00
James Prestwood
eb3345b51b eap-mschapv2: Check Password-Hash exists when loading settings
Caught by static analysis, the Password-Hash was never validated so
it could end up memcpying from a NULL pointer.
2024-03-11 22:08:02 -05:00
James Prestwood
795f57e816 p2p: check connected peer before processing request
Caught by static analysis, the dev->conn_peer pointer was being
dereferenced very early on without a NULL check, but further it
was being NULL checked. If there is a possibility of it being NULL
the check should be done much earlier.
2024-03-11 22:07:37 -05:00
James Prestwood
71a7190ed2 eap-mschapv2: remove unneeded initialization 2024-03-04 13:48:08 -06:00
James Prestwood
405b897687 dpp: check wrapped data exists in authenticate response 2024-03-04 13:48:08 -06:00
James Prestwood
62e2a3535d files: remove unneeded initialization 2024-03-04 13:48:08 -06:00
James Prestwood
d9aaf6c842 ie: remove unneeded initialization 2024-03-04 13:48:08 -06:00
James Prestwood
b7559d68c7 client: remove unneeded initialization 2024-03-04 13:48:08 -06:00
Marcel Holtmann
8bb3e3c4fa Release 2.16 2024-03-04 08:51:22 +01:00
James Prestwood
c76f7eac05 auto-t: add ability to reserve radios not for IWD/hostapd/etc
If the test needs to do something very specific it may be useful to
prevent IWD from managing all the radios. This can now be done
by setting a "reserve" option in the radio settings. The value of
this should be something other than iwd, hostapd, or wpa_supplicant.

For example:

[rad1]
reserve=false
2024-03-01 08:42:02 -06:00
James Prestwood
c2ad0006eb ap: bail in ap_del_station if AP is going down
Caught by static analysis, if this condition is met the AP is going
down so we cannot continue further accessing the ap object.
2024-02-29 14:37:49 -06:00
James Prestwood
5fcfb430b2 ap: verify ATTR_MAC exists in NEW_STATION
Caught by static analysis, if ATTR_MAC was not in the message there
would be a memcpy with uninitialized bytes. In addition there is no
reason to memcpy twice. Instead 'mac' can be a const pointer which
both verifies it exists and removes the need for a second memcpy.
2024-02-29 14:37:42 -06:00
James Prestwood
3a17c8e3c5 nl80211util: check l_genl_attr_recurse return in extract_nested
Caught by static analysis, the recurse operation return was not being
checked.
2024-02-29 14:37:29 -06:00
James Prestwood
6febe5bed1 ap: allow va_end to get called in ap_handshake_event
Caught by static analysis, va_end was never being called since the
REKEY_COMPLETE event was returning early.
2024-02-29 14:37:19 -06:00
James Prestwood
338577bb3a ap: check that the last band_freq_attrs was set
Static analysis complains that 'last' could be NULL which is true.
This really could only happen if every frequency was disabled which
likely is impossible but in any case, check before dereferencing
the pointer.
2024-02-29 14:37:01 -06:00
James Prestwood
83c032a583 p2putil: check length of client info description
A length check was missing which could cause a out of bounds read.

Co-authored-by: Alex Radocea <alex@supernetworks.org>
2024-02-29 14:36:16 -06:00
James Prestwood
d34b4e16e0 p2putil: initialize all parsing structures to zero
Since these are all stack variables they are not zero initialized.
If parsing fails there may be invalid pointers within the structures
which can get dereferenced by p2p_clear_*
2024-02-29 14:33:23 -06:00
James Prestwood
52a47c9fd4 p2putil: fix crash/remove side effect parsing adv service info
The input queue pointer was being initialized unconditionally so if
parsing fails the out pointer is still set after the queue is
destroyed. This causes a crash during cleanup.

Instead use a temporary pointer while parsing and only after parsing
has finished do we set the out pointer.

Reported-By: Alex Radocea <alex@supernetworks.org>
2024-02-29 14:32:53 -06:00
James Prestwood
816d258cab auto-t: Add frame fuzzing test
Add a test to validate a crash found by Alex Radocea when sending
a fuzzed beacon frame.

Co-authored-by: Alex Radocea <alex@supernetworks.org>
2024-02-29 14:32:33 -06:00
James Prestwood
5067654a6d auto-t: end process_io on HUP signal, detect process crash
When HUP is received the IO read callback was never completing which
caused it to block indefinitely until waited for. This didn't matter
for most transient processes but for IWD, hostapd, wpa_supplicant
it would cause test-runner to hang if the process crashed.

Detecting a crash is somewhat hacky because we have no process
management like systemd and the return code isn't reliable as some
processes return non-zero under normal circumstances. So to detect
a crash the process output is being checked for the string:
"++++++++ backtrace ++++++++". This isn't 100% reliable obviously
since its dependent on how the binary is compiled, but even if the
crash itself isn't detected any test should still fail if written
correctly.

Doing this allows auto-tests to handle IWD crashes gracefully by
failing the test, printing the exception (event without debugging)
and continue with other tests.
2024-02-29 14:31:55 -06:00
Denis Kenzior
aef394895d netconfig: Fix copy-paste error
netconfig_domains_update() was setting dns_list instead of the domains
member.
2024-02-28 11:51:33 -06:00
James Prestwood
cdbd59103e auto-t: fix netconfig to handle resolvconf values out of order
The slaac_test was one that would occationally fail, but very rarely,
due to the resolvconf log values appearing in an unexpected order.

This appears to be related to a typo in netconfig-commit which would
not set netconfig-domains and instead set dns_list. This was fixed
with a pending patch:

https://lore.kernel.org/iwd/20240227204242.1509980-1-denkenz@gmail.com/T/#u

But applying this now leads to testNetconfig failing slaac_test
100% of the time.

I'm not familiar enough with resolveconf to know if this test change
is ok, but based on the test behavior the expected log and disk logs
are the same, just in the incorrect order. I'm not sure if this the
log order is deterministic so instead the check now iterates the
expected log and verifies each value appears once in the resolvconf
log.

Here is an example of the expected vs disk logs after running the
test:

Expected:

-a wlan1.dns
nameserver 192.168.1.2
nameserver 3ffe:501:ffff💯:10
nameserver 3ffe:501:ffff💯:50
-a wlan1.domain
search test1
search test2

Resolvconf log:

-a wlan1.domain
search test1
search test2
-a wlan1.dns
nameserver 192.168.1.2
nameserver 3ffe:501:ffff💯:10
nameserver 3ffe:501:ffff💯:50
2024-02-28 11:50:54 -06:00
Denis Kenzior
52c6a6b8ea eap-wsc: Zero authenticator bytes to fix static analysis warning
static analysis complains that authenticator is used uninitialized.
This isn't strictly true as memory region is reserved for the
authenticator using the contents of the passed in structure.  This
region is then overwritten once the authenticator is actually computed
by authenticator_put().  Silence this warning by explicitly setting
authenticator bytes to 0.

Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
2024-02-28 09:13:30 -06:00
James Prestwood
42273fd122 station: warn on missing scan_bss in station_transition_start
This shouldn't be possible in theory since the roam_bss_list being
iterated is a subset of entire scan_bss list station/network has
but to be safe, and catch any issues due to future changes warn on
this condition.
2024-02-27 16:04:11 -06:00
James Prestwood
14aa333a39 crypto: fix uninitialized variable coverity warning
Same as for aes_siv_decrypt, check num_ads before calling memcpy.
2024-02-27 16:04:11 -06:00
James Prestwood
ee52968043 crypto: fix uninitialized variable coverity warning
For some encrypt operations DPP passes no AD iovecs (both are
NULL/0). But since the iovec itself is on the stack 'ad' is a
valid pointer from within aes_siv_encrypt. This causes memcpy
to be called which coverity complains about. Since the copy
length is zero it was effectively a no-op, but check num_ad to
prevent the call.
2024-02-27 14:33:33 -06:00
James Prestwood
d13af0a4a2 unit: fix memory leak in test-dpp 2024-02-27 14:33:29 -06:00
James Prestwood
9f18bf402c auto-t: add OWE test for auto default group 2024-02-27 13:55:37 -06:00
James Prestwood
9d4c34dc7a auto-t: Add test for new SAE default group behavior
Tests the 3 possible options to UseDefaultEccGroup behave as
expected:
 - When not provided use the "auto" behavior.
 - When false, always use higher order groups
 - When true, always use default group
2024-02-27 13:55:37 -06:00
James Prestwood
e296a61e3f auto-t: refactor/fix testSAE
The SAE test made some assumptions on certain conditions due to
there being no way of checking if those conditions were met
Mainly the use of H2E/hunt-and-peck.

We assumed that when we told hostapd to use H2E or hunt/peck it
would but in reality it was not. Hostapd is apparently not very
good at swapping between the two with a simple "reload" command.
Once H2E is enabled it appears that it cannot be undone.
Similarly the vendor elements seem to carry over from test to
test, and sometimes not which causes unintended behavior.

To fix this create separate APs for the specific scenario being
tested:
 - Hunt and peck
 - H2E
 - Special vendor_element simulating buggy APs

Another issue found was that if password identifies are used
hostapd automatically chooses H2E which was not intented, at
least based on the test names (in reality it wasn't causing any
problems).

The tests have also been improved to use hostapds "sta_status"
command which contains the group number used when authenticating,
so now that at least can be verified.
2024-02-27 13:55:37 -06:00
James Prestwood
82161909a1 auto-t: add HostapdCLI.sta_status
Gets information about a specific STA hostapd is tracking. This
object will contain detailed information such as the SAE group
number used.
2024-02-27 13:55:37 -06:00
James Prestwood
c2ef5f3f68 auto-t: add Device.event_ocurred
Checks that an event happened previously, and consumes events. This
is useful for checking that an event did not happen after some
testing operations.
2024-02-27 13:55:37 -06:00
James Prestwood
fba4ee90d0 netdev: add NETDEV_EVENT_ECC_GROUP_RETRY, handle in station
In order to complete the learned default group behavior station needs
to be aware of when an SAE/OWE connection retried. This is all
handled within netdev/sae so add a new netdev event so station can
set the appropriate network flags to prevent trying the non-default
group again.
2024-02-27 13:55:37 -06:00
James Prestwood
a559bd7c40 sae: remove sae_sm_set_force_group_19, use handshake
Use the flag set into the handshake to force the default ECC group
2024-02-27 13:55:37 -06:00
James Prestwood
988f68e916 network: set use default ECC group in handshake setup
If either the settings specify it, or the scan_bss is flagged, set
the use_default_ecc_group flag in the handshake.

This also renames the flag to cover both OWE and SAE
2024-02-27 13:55:37 -06:00
James Prestwood
b38f71f221 network: retain default ECC group for OWE after setting
There is special handling for buggy OWE APs which set a network flag
to use the default OWE group. Utilize the more persistent setting
within known-networks as well as the network object (in case there
is no profile).

This also renames the get/set APIs to be generic to ECC groups rather
than only OWE.
2024-02-27 13:55:37 -06:00
James Prestwood
3f04bc427d knownnetworks: add option to force a default ECC group
This adds the option [Settings].UseDefaultEccGroup which allows a
network profile to specify the behavior when using an ECC-based
protocol. If unset (default) IWD will learn the behavior of the
network for the lifetime of its process.

Many APs do not support group 20 which IWD tries first by default.
This leads to an initial failure followed by a retry using group 19.
This option will allow the user to configure IWD to use group 19
first or learn the network capabilities, if the authentication fails
with group 20 IWD will always use group 19 for the process lifetime.
2024-02-27 13:55:37 -06:00
James Prestwood
3ab09e0ae2 doc: Document UseDefaultEccGroup 2024-02-27 13:55:37 -06:00
Marcel Holtmann
cc0fcb2bb4 Release 2.15 2024-02-26 20:55:02 +01:00
Marcel Holtmann
b1edef3a14 build: Require at least version 0.63 when building with external ELL 2024-02-26 20:50:33 +01:00
Ram Subramanian
c0058c07bf doc: document channel field in station diagnostics 2024-02-26 09:44:38 -06:00
Ram Subramanian
9f31663e21 client: report channel if present in diag message 2024-02-26 09:44:25 -06:00
Ram Subramanian
793228028d station: add channel number to diagnostics message
As a small convenience to the user.
2024-02-26 09:44:12 -06:00
James Prestwood
d4c68d7d83 netdev: add notice events for connection timeouts
The information specific to auth/assoc/connect timeouts isn't
communicated to station so emit the notice events within netdev.
We could communicate this to station by adding separate netdev
events, but this does not seem worth it for this use case as
these notice events aren't strictly limited to station.
2024-02-22 10:15:07 -06:00
James Prestwood
77cdbd186b station: use iwd_notice for state/event information
For anyone debugging or trying to identify network infrastructure
problems the IWD DBus API isn't all that useful and ultimately
requires going through debug logs to figure out exactly what
happened. Having a concise set of debug logs containing only
relavent information would be very useful. In addition, having
some kind of syntax for these logs to be parsed by tooling could
automate these tasks.

This is being done, starting with station, by using iwd_notice
which internally uses l_notice. The use of the notice log level
(5) in IWD will be strictly for the type of messages described
above.
2024-02-22 10:15:04 -06:00
James Prestwood
98ae3d4197 doc: document use of l_log APIs
With the introduction of l_notice in IWD some guidelines need to be
set for l_info, l_warn, l_error, l_debug and l_notice.
2024-02-22 10:15:02 -06:00
James Prestwood
d8a6fb86c1 iwd: add iwd_notice for special event/state type of logging
iwd_notice is being added so modules can communicate internal
state or event information via the NOTICE log level. This log
level will be reserved in IWD for only these type of messages.

The iwd_notice macro aims to help enforce some formatting
requirements for these type of log messages. The messages
should be one or more comma-separated "key: value" pairs starting
with "event: <name>" and followed by any additional info that
pertains to that event.

iwd_notice only enforces the initial event key/value format and
additional arguments are left to the caller to be formatted
correctly.
2024-02-22 10:14:59 -06:00
James Prestwood
32f3745745 main: add runtime flag for setting the logger
The --logger,-l flag can now be used to specify the logger type.
Unset (default) will set log output to stderr as it is today. The
other valid options are "syslog" and "journal".
2024-02-22 10:14:41 -06:00
James Prestwood
c54ef5a8da auto-t: timestamp log files in test-runner
The log files become much more useful when there are timestamps
associated with each log.
2024-02-22 09:28:55 -06:00
James Prestwood
a507c08bfe auto-t: fix failed_roam_test to pass when run on its own
When running this test with others the hostapd neighbors are already
grouped which lets the test pass. On its own this does not happen
and it fails.
2024-02-22 09:28:55 -06:00
Denis Kenzior
ba5a6df2d1 wiphy: Remove basename() use
basename use is considered harmful.  There are two versions of
basename (see man 3 basename for details).  The more intuitive version,
which is currently being used inside wiphy.c, is not supported by musl
libc implementation.  Use of the libgen version is not preferred, so
drop use of basename entirely.  Since wiphy.c is the only call site of
basename() inside iwd, open code the required logic.
2024-02-14 14:50:06 -06:00
James Prestwood
6315b42861 netdev: use reason code from netdev_deauthenticate_event
The reason code was not being passed to netdev_connect_failed as
it should have been.
2024-02-13 17:00:39 -06:00
Marcel Holtmann
42b4da1be2 Release 2.14 2024-02-09 22:13:55 +01:00
Marcel Holtmann
bcfbaa096d build: Require at least version 0.62 when building with external ELL 2024-02-09 22:09:38 +01:00
James Prestwood
593c9dee6c auto-t: add netconfig timeout test
Tests that netconfig eventually times out and that IWD disconnects
2024-01-30 14:00:30 -06:00
James Prestwood
aa0a439856 netconfig: limit DHCPv4 attempts to avoid extended netconfig times
ELL now has a setting to limit the number of DHCP attempts. This
will now be set in IWD and if reached will result in a failure
event, and in turn a disconnect.

IWD will set a maximum of 4 retries which should keep the maximum
DHCP time to ~60 seconds roughly.
2024-01-30 13:59:22 -06:00
James Prestwood
1fe68aef0b station: reverse roam scan results for sorted known frequencies
The known frequency list is now a sorted list and the roam scan
results were not complying with this new requirement. The fix is
easy though since the iteration order of the scan results does
not matter (the roam candidates are inserted by rank). To fix
the known frequencies order we can simply reverse the scan results
list before iterating it.
2024-01-30 13:58:45 -06:00
James Prestwood
643503eeea netdev: make unprotected disconnect debug log more clear
The debug log was just saying "disconnect event" but we should
distinguish between unprotected and protected events.
2024-01-30 13:58:45 -06:00
James Prestwood
085a2511f6 netdev: fix setting a uint8_t with l_get_le16 2024-01-30 13:58:45 -06:00
Mathy Vanhoef
6415420f1c ap: only accept ptk 4/4 after receiving ptk 2/4
When operating as an AP, drop message 4 of the 4-way handshake if the AP
has not yet received message 2. Otherwise an attacker can skip message 2
and immediately send message 4 to bypass authentication (the AP would be
using an all-zero ptk to verify the authenticity of message 4).
2024-01-29 21:00:00 -06:00
James Prestwood
1a79092383 auto-t: add test for known frequency sorting/maximum
Modify the existing frequency test to check that the ordering
lines up with the ranking of the BSS.

Add a test to check that quick scans limit the number of known
frequencies.
2024-01-29 20:45:32 -06:00
James Prestwood
f52180d41c station: knownnetworks: limit quick scans to 5 freqs per network
In very large network deployments there could be a vast amount of APs
which could create a large known frequency list after some time once
all the APs are seen in scan results. This then increases the quick
scan time significantly, in the very worst case (but unlikely) just
as long as a full scan.

To help with this support in knownnetworks was added to limit the
number of frequencies per network. Station will now only get 5
recent frequencies per network making the maximum frequencies 25
in the worst case (~2.5s scan).

The magic values are now defines, and the recent roam frequencies
was also changed to use this define as well.
2024-01-29 20:43:33 -06:00
James Prestwood
197087d081 station: use network_update_known_frequencies
Updates each network with its new, most current, set of BSS's
for the different types of scans: dbus/autoconnect, hidden, and
OWE.
2024-01-29 20:43:21 -06:00
James Prestwood
d03b06db85 network: add network_update_known_frequencies
In order to support an ordered list of known frequencies the list
should be in order of last seen BSS frequencies with the highest
ranked ones first. To accomplish this without adding a lot of
complexity the frequencies can be pushed into the list as long as
they are pushed in reverse rank order (lowest rank first, highest
last). This ensures that very high ranked BSS's will always get
superseded by subsequent scans if not seen.

This adds a new network API to update the known frequency list
based on the current newtork->bss_list. This assumes that station
always wipes the BSS list on scans and populates with only fresh
BSS entries. After the scan this API can be called and it will
reverse the list, then add each frequency.
2024-01-29 20:43:02 -06:00
Marcel Holtmann
4b3e82f742 Release 2.13 2024-01-12 20:07:31 +01:00
Fiona Klute
a6638513d4 Log falling back from SAE to WPA2
I've had connections to a WPA3-Personal only network fail with no log
message from iwd, and eventually figured out to was because the driver
would've required using CMD_EXTERNAL_AUTH. With the added log messages
the reason becomes obvious.

Additionally the fallback may happen even if the user explicitly
configured WPA3 in NetworkManager, I believe a warning is appropriate
there.
2024-01-09 21:32:28 -06:00
James Prestwood
5abf54f2dc auto-t: add test for roaming + netconfig
This test ensures IWD will continue to roam and restart netconfig if
roam conditions are met prior to netconfig finishing.
2024-01-08 22:08:53 -06:00
James Prestwood
7080a4453e station: add handling for new NETCONFIG state
There was an unhandled corner case if netconfig was running and
multiple roam conditions happened in sequence, all before netconfig
had completed. A single roam before netconfig was already handled
(23f0f5717c) but this did not take into account any additional roam
conditions.

If IWD is in this state, having started netconfig, then roamed, and
again restarted netconfig it is still in a roaming state which will
prevent any further roams. IWD will remain "stuck" on the current
BSS until netconfig completes or gets disconnected.

In addition the general state logic is wrong here. If IWD roams
prior to netconfig it should stay in a connecting state (from the
perspective of DBus).

To fix this a new internal station state was added (no changes to
the DBus API) to distinguish between a purely WiFi connecting state
(STATION_STATE_CONNECTING/AUTO) and netconfig
(STATION_STATE_NETCONFIG). This allows IWD roam as needed if
netconfig is still running. Also, some special handling was added so
the station state property remains in a "connected" state until
netconfig actually completes, regardless of roams.

For some background this scenario happens if the DHCP server goes
down for an extended period, e.g. if its being upgraded/serviced.
2024-01-08 22:04:53 -06:00
James Prestwood
8f7443b0b3 station: add additional internal state, STATION_STATE_NETCONFIG
This is still treated as "connecting" from a DBus perspective but
will allow for better handling internally for some roaming corner
cases.
2024-01-08 22:04:41 -06:00
James Prestwood
407a8a4441 client: fix AP PairwiseCiphers parsing
This property was being parsed as "s" when it should be "as". This
results in "ap <wlan> show" having an empty entry for the
PairwiseCiphers list.
2024-01-04 12:18:40 -06:00
James Prestwood
705898d1db monitor: include unistd.h in main.c
This fixes a build break on some systems, specifically the
raspberry Pi 3 (ARM):

monitor/main.c: In function ‘open_packet’:
monitor/main.c:176:3: error: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Werror=implicit-function-declaration]
  176 |   close(fd);
      |   ^~~~~
      |   pclose
2024-01-04 12:18:05 -06:00
James Prestwood
aaf1d91d51 auto-t: fix random testPSK-roam failure
This was caused by the unused hostapd instance running after being
re-enabled by mistake. This cause an additional scan result with the
same rank to be seen which would then be connected to by luck of the
draw.
2024-01-04 11:59:41 -06:00
James Prestwood
b0ad6158e1 auto-t: improve failure handling in testPSK-roam
This really needs to be done to many more autotests but since this
one seems to have random failures ensure that all the tests still
run if one fails. In addition add better cleanup for hwsim rules.
2024-01-04 11:59:37 -06:00
James Prestwood
0a3797a4d4 auto-t: update roam test to use new debug events 2024-01-04 11:57:32 -06:00
James Prestwood
77e5c94dc6 station: add debug events for internal states
This gives the tests a lot more fine-tune control to wait for
specific state transitions rather than only what is exposed over
DBus.

The additional events for "ft-roam" and "reassoc-roam" were removed
since these are now covered by the more generic state change events
("ft-roaming" and "roaming" respectively).
2024-01-04 11:57:28 -06:00
James Prestwood
593fad5260 station: handle netconfig after roaming for FW roams
This was not taken into account for FW roams and would result in the
station state being set to connected regardless of netconfig's result.
2024-01-04 11:46:39 -06:00
James Prestwood
a2fff11823 monitor: indicate if the MPDU was invalid
If the frame was not parsed as an MPDU indicate this in iwmon. This
also adds handling to print probe requests.
2024-01-02 11:02:15 -06:00
Denis Kenzior
cfb468e44d monitor: Move iwmon reading logic into main.c
To support multiple nlmon sources, move the logic that reads from iwmon
device into main.c instead of nlmon.  nlmon.c now becomes agnostic of
how the packets are actually obtained.  Packets are fed in via
high-level APIs such as nlmon_print_rtnl, nlmon_print_genl,
nlmon_print_pae.
2024-01-02 10:59:38 -06:00
Denis Kenzior
a5f5578a61 monitor: Use nlmon_print_* inside nlmon_receive
The current implementation inside nlmon_receive is asymmetrical.  RTNL
packets are printed using nlmon_print_rtnl while GENL packets are
printed using nlmon_message.

nlmon_print_genl and nlmon_print_rtnl already handle iterating over data
containing multiple messages, and are used by nlmon started in reader
mode.  Use these for better symmetry inside nlmon_receive.

While here, move store_netlink() call into nlmon_print_rtnl.  This makes
handling of PCAP output symmetrical for both RTNL and GENL packets.
This also fixes a possibility where only the first message of a
multi-RTNL packet would be stored.
2024-01-02 10:59:36 -06:00
Denis Kenzior
cc371641ed monitor: Remove unused PACKET_AUXDATA handling 2024-01-02 10:59:34 -06:00
Denis Kenzior
9ba6dac066 monitor: Remove unused code path
nlmon_print_genl invokes genl_ctrl when a generic netlink control
message is encountered.  genl_ctrl() tries to filter nl80211 family
appearance messages and setup nlmon->id with the extracted family id.
However, the id is already provided inside main.c by using nlmon_open,
and no control messages are processed by nlmon in 'capture' mode (-r
command line argument not passed) since all genl messages go through
nlmon_message() path instead.
2024-01-02 10:59:20 -06:00
Sam James
ba9717d445 configure.ac: fix bashism
configure scripts need to be runnable with a POSIX-compliant /bin/sh.

On many (but not all!) systems, /bin/sh is provided by Bash, so errors
like this aren't spotted. Notably Debian defaults to /bin/sh provided
by dash which doesn't tolerate such bashisms as '+='.

This retains compatibility with bash. Just copy the expanded append like
we do on the line above.

Fixes warnings like:
```
./configure: 13352: CFLAGS+= -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2: not found
```
2023-12-31 20:35:26 -06:00
Denis Kenzior
e89ba32d30 build: Fix build with openssl 3.2
make --no-print-directory all-am
openssl req -new -extensions cert_ext \
		-config ./unit/gencerts.cnf \
		-subj '/O=Foo Example Organization/CN=Foo Example Organization/emailAddress=foo@mail.example' \
		-key unit/cert-server-key.pem -out unit/cert-server.csr
Error adding request extensions from section cert_ext
4057AC4D6F7F0000:error:11000079:X509 V3 routines:v2i_AUTHORITY_KEYID:no issuer certificate:crypto/x509/v3_akid.c:156:
4057AC4D6F7F0000:error:11000080:X509 V3 routines:X509V3_EXT_nconf_int:error in extension:crypto/x509/v3_conf.c:48:section=cert_ext, name=authorityKeyIdentifier, value=keyid:always,issuer:always
make[1]: *** [Makefile:3962: unit/cert-server.csr] Error 1
2023-12-31 11:02:04 -06:00
Marcel Holtmann
a938313cba Release 2.12 2023-12-27 13:31:43 +01:00
James Prestwood
390fd58cad auto-t: increase RAM when running with valgrind (UML)
This was done for QEMU but not for UML. Running more than a few
tests with --valgrind will generally thrown an OOM error pretty
quick.
2023-12-19 19:48:51 -06:00
James Prestwood
0f1d9685e7 auto-t: add DPP tests to check extra settings are applied
In order to test that extra settings are applied prior to connecting
two tests were added for hidden networks as well as one testing if
there is already an existing profile after DPP.

The reason hidden networks were used was due to the requirement of
the "Hidden" settings in the profile. If this setting doesn't get
sync'ed to disk the connection will fail.
2023-12-19 19:48:45 -06:00
James Prestwood
8f5109c439 dpp: fix extra settings not being used when connecting
Before this change DPP was writing the credentials both to disk
and into the network object directly. This allowed the connection
to work fine but additional settings were not picked up due to
network_set_passphrase/psk loading the settings before they were
written.

Instead DPP can avoid setting the credentials to the network
object entirely and just write them to disk. Then, wait for
known networks to notify that the profile was either created
or updated then DPP can proceed to connecting. network_autoconnect()
will take care of loading the profile that DPP wrote and remove the
need for DPP to touch the network object at all.

One thing to note is that an idle callback is still needed from
within the known networks callback. This is because a new profile
requires network.c to set the network_info which is done in the
known networks callback. Rather than assume that network.c will be
called into before dpp.c an l_idle was added.
2023-12-19 12:41:50 -06:00
James Prestwood
7a76385ec9 knownnetworks: Add UPDATED event
If a known network is modified on disk known networks does not have
any way of notifying other modules. This will be needed to support a
corner case in DPP if a profile exists but is overwritten after DPP
configuration. Add this event to known networks and handle it in
network.c (though nothing needs to be done in that case).
2023-12-19 12:41:36 -06:00
Sergei Trofimovich
688d277008 dpp: fix data corruption around prf_plus() call
Without the change test-dpp fails on aarch64-linux as:

    $ unit/test-dpp
    TEST: DPP test responder-only key derivation
    TEST: DPP test mutual key derivation
    TEST: DPP test PKEX key derivation
    test-dpp: unit/test-dpp.c:514: test_pkex_key_derivation: Assertion `!memcmp(tmp, __tmp, 32)' failed.

This happens due to int/size_t type mismatch passed to vararg
parameters to prf_plus():

    bool prf_plus(enum l_checksum_type type, const void *key, size_t key_len,
               void *out, size_t out_len,
               size_t n_extra, ...)
    {
       // ...
       va_start(va, n_extra);

       for (i = 0; i < n_extra; i++) {
               iov[i + 1].iov_base = va_arg(va, void *);
               iov[i + 1].iov_len = va_arg(va, size_t);
       // ...

Note that varargs here could only be a sequence of `void *` / `size_t`
values.

But in src/dpp-util.c `iwd` attempted to pass `int` there:

   prf_plus(sha, prk, bytes, z_out, bytes, 5,
            mac_i, 6, // <- here
            mac_r, 6, // <- and here
            m_x, bytes,
            n_x, bytes,
            key, strlen(key));

aarch64 stores only 32-bit value part of the register:

    mov     w7, #0x6
    str     w7, [sp, #...]

and loads full 64-bit form of the register:

    ldr     x3, [x3]

As a result higher bits of `iov[].iov_len` contain unexpected values and
sendmsg sends a lot more data than expected to the kernel.

The change fixes test-dpp test for me.

While at it fixed obvious `int` / `size_t` mismatch in src/erp.c.

Fixes: 6320d6db0f ("crypto: remove label from prf_plus, instead use va_args")
2023-12-18 22:14:45 -06:00
James Prestwood
5af1fe34b6 network: remove 'path' from settings_load_pt_ecc
The path argument was used purely for debugging. It can be just as
informational printing just the SSID of the profile that failed to
parse the setting without requiring callers allocate a string to
call the function.
2023-12-15 10:21:44 -06:00
James Prestwood
63e35dbd88 auto-t: throw exception if executable is missing
Certain tests may require external processes to work
(e.g. testNetconfig) and if missing the test will just hang until
the maximum test timeout. Check in start_process if the exe
actually exists and if not throw an exception.
2023-12-15 10:21:01 -06:00
James Prestwood
60e165095a auto-t: add H2E password identifier test
In order to support identifiers the test profiles needed to be
reworked due to hostapd allowing multiple password entires. You
cannot just call set_value() with a new entry as the old ones
still exist. Instead use a unique password for the identifier and
non-identifier use cases.

After adding this test the failure_test started failing due to
hostapd not starting up. This was due to the group being unsupported
but oddly only when hostapd was reloaded (running the test
individually worked). To fix this the group number was changed to 21
which hostapd does support but IWD does not.
2023-12-15 10:21:01 -06:00
James Prestwood
da94b2c6a9 doc: document [Security].PasswordIdentifier 2023-12-15 10:21:01 -06:00
James Prestwood
3349cdd5f4 network: add support for SAE password identifiers
Adds a new network profile setting [Security].PasswordIdentifier.
When set (and the BSS enables SAE password identifiers) the network
and handshake object will read this and use it for the SAE
exchange.

Building the handshake will fail if:
 - there is no password identifier set and the BSS sets the
   "exclusive" bit.
 - there is a password identifier set and the BSS does not set
   the "in-use" bit.
2023-12-15 10:21:01 -06:00
Marcel Holtmann
e8e5d91e5a Release 2.11 2023-12-14 00:00:17 +01:00
James Prestwood
0979ff697a netdev: station: remove NETDEV_EVENT_FT_ROAMED
The notification for roaming success/failure is now handled with
the connect callback.
2023-12-13 10:12:53 -06:00
James Prestwood
393b6ee87b ft: remove ft_associate and helpers
The reassociation is done through netdev directly, these are no
longer needed.
2023-12-13 10:12:41 -06:00
James Prestwood
56dac6744b station: use netdev_ft_reassociate
Using this will provide netdev with a connect callback and unify the
roaming result notification between FT and reassociation. Both paths
will now end up in station_reassociate_cb.

This also adds another return case for ft_handshake_setup which was
previously ignored by ft_associate. Its likely impossible to actually
happen but should be handled nevertheless.

Fixes: 30c6a10f28 ("netdev: Separate connect_failed and disconnected paths")
2023-12-13 10:12:08 -06:00
James Prestwood
7b0cda76a9 netdev: add netdev_ft_reassociate
Essentially exposes (and renames) netdev_ft_tx_associate in order to
be called similarly to netdev_reassociate/netdev_connect where a
connect callback can be provided. This will fix the current bug where
if association times out during FT IWD will hang and never transition
to disconnected.

This also removes the calling of the FT_ROAMED event and instead just
calls the connect callback (since its now set). This unifies the
callback path for reassociation and FT roaming.
2023-12-13 10:10:46 -06:00
James Prestwood
4efd1a1702 ft: add ft_handshake_setup
This will be called from station after FT-authentication has
finished. It sets up the handshake object to perform reassociation.

This is essentially a copy-paste of ft_associate without sending
the actual frame.
2023-12-13 10:09:52 -06:00
James Prestwood
cf137f4199 ft: add FTE/RSNE building to ft_prepare_handshake
In preparation to remove ft_associate build the FTE/RSNE in
ft_prepare_handshake and set into the handshake object directly.
2023-12-13 10:09:03 -06:00
James Prestwood
0a0a257e1e handshake: remove handshake_state_set_fte
Replaced by set_authenticator_fte
2023-12-13 10:08:53 -06:00
James Prestwood
4f80e8baef unit: use authenticator_fte 2023-12-13 10:08:44 -06:00
James Prestwood
6b677e8db0 handshake: use authenticator_fte instead of 'fte' 2023-12-13 10:08:06 -06:00
James Prestwood
a7fe6a9c12 handshake: add setters for authenticator/supplicant_fte
In general only the authenticator FTE is used/validated but with
some FT refactoring coming there needs to be a way to build the
supplicants FTE into the handshake object. Because of this there
needs to be separate FTE buffers for both the authenticator and
supplicant.
2023-12-13 10:07:28 -06:00
James Prestwood
d756e60f24 auto-t: only call set_value for changed values in default()
The default() method was added for convenience but was extending the
test times significantly when the hostapd config was lengthy. This
was because it called set_value for every value regardless if it
had changed. Instead store the current configuration and in default()
only reset values that differ.
2023-12-13 10:07:23 -06:00
James Prestwood
65a03d8049 auto-t: add association timeout test
This tests ensures IWD disconnects after receiving an association
timeout event. This exposes a current bug where IWD does not
transition to disconnected after an association timeout when
FT-roaming.
2023-12-13 10:07:20 -06:00
James Prestwood
5a426433dd auto-t: add explicit stop() to IWD class
If tests end in an unknown state it is sometimes required that IWD
be stopped manually in order for future tests to run. Add a stop()
method so test tearDown() methods can explicitly stop IWD.
2023-12-13 10:07:18 -06:00
James Prestwood
84d018e722 auto-t: fix SignalAgent Release arguments
The path for IWD to call this doesn't ever happen in autotests
but during debugging of the DPP agent it was noticed that the
DBus signature was incorrect and would always result in an error
when calling from IWD.
2023-12-13 10:06:32 -06:00
James Prestwood
0dd2f0000e dpp: set "" arguments to Release method call
Without this the DBus message does not initialize the message
correctly which causes future DBus calls to fail.
2023-12-13 10:06:07 -06:00
James Prestwood
ded1a35c41 sae: add debugging for incorrect password identifier
If the AP rejects the auth because of an unknown identifier catch
this and log the error.
2023-12-06 10:58:44 -06:00
James Prestwood
3524b5ef43 mpdu: add unknown password identifier status 2023-12-06 10:58:38 -06:00
James Prestwood
737ebf437f sae: include password identifier IE in commit
Include the IE if a password identifier is being used. This is only
supported by H2E as required by 802.11.
2023-12-06 10:58:13 -06:00
James Prestwood
c1d40e2263 handshake: add password identifier/setter 2023-12-06 10:52:28 -06:00
James Prestwood
62dad5e792 network: pass scan_bss into network_load_psk
For adding SAE password identifiers the capability bits need to be
verified when loading the identifier from the profile. Pass the
BSS object in to network_load_psk rather than the 'need_passphrase'
boolean.
2023-12-06 10:45:46 -06:00
James Prestwood
2d26304663 scan: parse password identifier/exclusive bits
These bits are used to communicate to the station that SAE password
identifiers are used or required.
2023-12-06 10:44:45 -06:00
Denis Kenzior
195d1f8720 netdev: Remove vendor_ies from netdev_connect signature
The vendor IEs are now passed in the handshake_state object instead.
2023-11-30 17:10:01 -06:00
Denis Kenzior
0bb181a368 wsc: Use handshake to pass vendor ies
Instead of passing them directly via netdev_connect
2023-11-30 17:09:57 -06:00
Denis Kenzior
788c7ed010 p2p: Use handshake to pass vendor ies
Instead of passing them directly via netdev_connect
2023-11-30 17:09:45 -06:00
Denis Kenzior
fda946e070 netdev: iov_ie_append: Support iovecs with multiple IEs
iov_ie_append assumed that a single IE was being added and thus the
length of the IE could be extracted directly from the element.  However,
iov_ie_append was used on buffers which could contain multiple IEs
concatenated together, for example in handshake_state::vendor_ies.  Most
of the time this was safe since vendor_ies was NULL or contained a
single element, but would result in incorrect behavior in the general
case.  Fix that by changing iov_ie_append signature to take an explicit
length argument and have the caller specify whether the element is a
single IE or multiple.

Fixes: 7e9971661bcb ("netdev: Append any vendor IEs from the handshake")
2023-11-30 17:08:03 -06:00
Denis Kenzior
ba0d35ff38 p2p: Simplify cleanup of ies
Use an _auto_ variable to cleanup IEs allocated by
p2p_build_association_req().  While here, take out unneeded L_WARN_ON
since p2p_build_association_req cannot fail.
2023-11-30 17:06:14 -06:00
Denis Kenzior
305c4113e8 p2p: Simplify handshake_state cleanup 2023-11-30 17:06:12 -06:00
Denis Kenzior
78a39e926f handshake: Add cleanup function for handshake_state
To allow _auto_(handshake_state_free) variables to be used.
2023-11-30 17:06:11 -06:00
Marcel Holtmann
52e6a7c2ee Release 2.10 2023-11-27 16:58:45 +01:00
Marcel Holtmann
8ab24b423b build: Require at least version 0.61 when building with external ELL 2023-11-27 16:33:34 +01:00
James Prestwood
e3b5522769 station: fix crash when deauth comes before FT work completes
If the FT-Authenticate frame has been sent then a deauth is received
the work item for sending the FT-Associate frame is never canceled.
When this runs station->connected_network is NULL which causes a
crash:

src/station.c:station_try_next_transition() 7, target xx:xx:xx:xx:xx:xx
src/wiphy.c:wiphy_radio_work_insert() Inserting work item 5843
src/wiphy.c:wiphy_radio_work_insert() Inserting work item 5844
src/wiphy.c:wiphy_radio_work_done() Work item 5842 done
src/wiphy.c:wiphy_radio_work_next() Starting work item 5843
src/netdev.c:netdev_mlme_notify() MLME notification Remain on Channel(55)
src/ft.c:ft_send_authenticate()
src/netdev.c:netdev_mlme_notify() MLME notification Frame TX Status(60)
src/netdev.c:netdev_link_notify() event 16 on ifindex 7
src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
src/netdev.c:netdev_mlme_notify() MLME notification Deauthenticate(39)
src/netdev.c:netdev_deauthenticate_event()
src/netdev.c:netdev_mlme_notify() MLME notification Disconnect(48)
src/netdev.c:netdev_disconnect_event()
Received Deauthentication event, reason: 7, from_ap: true
src/station.c:station_disconnect_event() 7
src/station.c:station_disassociated() 7
src/station.c:station_reset_connection_state() 7
src/station.c:station_roam_state_clear() 7
src/netconfig.c:netconfig_event_handler() l_netconfig event 2
src/netconfig-commit.c:netconfig_commit_print_addrs() removing address: yyy.yyy.yyy.yyy
src/resolve.c:resolve_systemd_revert() ifindex: 7
[DHCPv4] l_dhcp_client_stop:1264 Entering state: DHCP_STATE_INIT
src/station.c:station_enter_state() Old State: connected, new state: disconnected
src/station.c:station_enter_state() Old State: disconnected, new state: autoconnect_quick
src/wiphy.c:wiphy_radio_work_insert() Inserting work item 5845
src/netdev.c:netdev_mlme_notify() MLME notification Cancel Remain on Channel(56)
src/wiphy.c:wiphy_radio_work_done() Work item 5843 done
src/wiphy.c:wiphy_radio_work_next() Starting work item 5844

"Program terminated with signal SIGSEGV, Segmentation fault.",
"#0  0x0000565359ee3f54 in network_bss_find_by_addr ()",
"#0  0x0000565359ee3f54 in network_bss_find_by_addr ()",
"#1  0x0000565359ec9d23 in station_ft_work_ready ()",
"#2  0x0000565359ec0af0 in wiphy_radio_work_next ()",
"#3  0x0000565359f20080 in offchannel_mlme_notify ()",
"#4  0x0000565359f4416b in received_data ()",
"#5  0x0000565359f40d90 in io_callback ()",
"#6  0x0000565359f3ff4d in l_main_iterate ()",
"#7  0x0000565359f4001c in l_main_run ()",
"#8  0x0000565359f40240 in l_main_run_with_signal ()",
"#9  0x0000565359eb3888 in main ()"
2023-11-27 09:23:26 -06:00
Denis Kenzior
bdaae53cf8 erp: Fix buffer overflow for 32 byte SSIDs
ssid is declared as a 32 byte field in handshake_state, hence using it
as a string which is assumed to be nul-terminated will fail for SSIDs
that are 32 bytes long.

Fixes: d938d362b212 ("erp: ERP implementation and key cache move")
Fixes: 433373fe28a4 ("eapol: cache ERP keys on EAP success")
2023-11-27 11:27:26 +01:00
Denis Kenzior
8d68b33e76 netdev: Fix buffer overflow with 32 character ssids
ssid is declared as a 32 byte field in handshake_state, hence using it
as a string which is assumed to be nul-terminated will fail for SSIDs
that are 32 bytes long.

Fixes: 1f1478285725 ("wiphy: add _generate_address_from_ssid")
Fixes: 5a1b1184fca6 ("netdev: support per-network MAC addresses")
2023-11-27 11:27:26 +01:00
Denis Kenzior
290f294c60 netdev: Do not leak l_genl_msg on error
In netdev_retry_owe, if l_gen_family_send fails, the connect_cmd is
never freed or reset.  Fix that.

While here, use a stack variable instead of netdev member, since the use
of such a member is unnecessary and confusing.
2023-11-27 11:27:26 +01:00
Denis Kenzior
5ce1c0d001 netdev: Don't duplicate vendor_ies
vendor_ies stored in handshake_state are already added as part of
netdev_populate_common_ies(), which is already invoked by
netdev_build_cmd_connect().

Normally vendor_ies is NULL for OWE connections, so no IEs are
duplicated as a result.
2023-11-27 11:27:26 +01:00
Denis Kenzior
b10ef09186 nl80211util: Move nl80211_append_rsn_attributes 2023-11-27 11:27:26 +01:00
Denis Kenzior
5a4fc931e7 ie: Move AKM suite converter from netdev
It is more logical to host this function inside ie.c than netdev.c.
Particularly since ie_rsn_cipher_suite_to_cipher is already present in
ie.c.
2023-11-27 11:27:26 +01:00
Denis Kenzior
44e9816dcb adhoc: Fix compilation on old systems
CC       src/adhoc.o
In file included from src/adhoc.c:28:0:
/usr/include/linux/if.h:234:19: error: field ‘ifru_addr’ has incomplete type
   struct sockaddr ifru_addr;
                   ^
/usr/include/linux/if.h:235:19: error: field ‘ifru_dstaddr’ has incomplete type
   struct sockaddr ifru_dstaddr;
                   ^
/usr/include/linux/if.h:236:19: error: field ‘ifru_broadaddr’ has incomplete type
   struct sockaddr ifru_broadaddr;
                   ^
/usr/include/linux/if.h:237:19: error: field ‘ifru_netmask’ has incomplete type
   struct sockaddr ifru_netmask;
                   ^
/usr/include/linux/if.h:238:20: error: field ‘ifru_hwaddr’ has incomplete type
   struct  sockaddr ifru_hwaddr;
                    ^
2023-11-27 11:26:52 +01:00
James Prestwood
a40d5199a8 netdev: move power save disabling until after interface is up
Very rarely on ath10k (potentially other ath cards), disabling
power save while the interface is down causes a timeout when
bringing the interface back up. This seems to be a race in the
driver or firmware but it causes IWD to never start up properly
since there is no retry logic on that path.

Retrying is an option, but a more straight forward approach is
to just reorder the logic to set power save off after the
interface is already up. If the power save setting fails we can
just log it, ignore the failure, and continue. From a users point
of view there is no real difference in doing it this way as
PS still gets disabled prior to IWD connecting/sending data.

Changing behavior based on a buggy driver isn't something we
should be doing, but in this instance the change shouldn't have
any downside and actually isn't any different than how it has
been done prior to the driver quirks change (i.e. use network
manager, iw, or iwconfig to set power save after IWD starts).

For reference, this problem is quite rare and difficult to say
exactly how often but certainly <1% of the time:

iwd[1286641]: src/netdev.c:netdev_disable_ps_cb() Disabled power save for ifindex 54
kernel: ath10k_pci 0000:02:00.0: wmi service ready event not received
iwd[1286641]: Error bringing interface 54 up: Connection timed out
kernel: ath10k_pci 0000:02:00.0: Could not init core: -110

After this IWD just sits idle as it has no interface to start using.

This is even reproducable outside of IWD if you loop and run:

ip link set <wlan> down
iw dev <wlan> set power_save off
ip link set <wlan> up

Eventually the 'up' command will fail with a timeout.

I've brought this to the linux-wireless/ath10k mailing list but
even if its fixed in future kernels we'd still need to support
older kernels, so a workaround/change in IWD is still required.
2023-11-23 09:21:36 -06:00
Marcel Holtmann
400782b6e4 Release 2.9 2023-11-19 18:53:15 +01:00
Marcel Holtmann
ca0806438b build: Require at least version 0.60 when building with external ELL 2023-11-19 18:36:14 +01:00
James Prestwood
aaaa3d1800 dbus: add SharedCodeAgent interface to iwd-dbus.conf 2023-11-17 14:13:31 -06:00
James Prestwood
5e1f19fca7 doc: document additional NotSupported shared code return 2023-11-17 10:51:23 -06:00
James Prestwood
5e0a97b197 dpp: fail early if multicast frame registration is unsupported
This is done already for DPP, do the same for PKEX. Few drivers
(ath9k upstream, ath10k/11k in progress) support this which is
unfortunate but since a configurator will not work without this
capability its best to fail early.
2023-11-17 10:51:23 -06:00
James Prestwood
cac10b52fc json: fix comment typo, "json_object_is_valid"
This should be json_iter_is_valid.
2023-11-17 09:49:12 -06:00
James Prestwood
4b147217ac auto-t: add checks for DPP 3rd party settings
Ensure the newly configured profile contains the additional
SendHostname setting that the configurator sends.
2023-11-17 09:49:06 -06:00
James Prestwood
6afda046c2 dpp: include 3rd party settings in network profile
If the configuration object contained IWD's 3rd party settings set
those into the network profile.
2023-11-17 09:48:58 -06:00
James Prestwood
87055f5a02 dpp-util: add support for 3rd party JSON fields
The DPP spec allows 3rd party fields in the DPP configuration
object (section 4.5.2). IWD can take advantage of this (when
configuring another IWD supplicant) to communicate additional
profile options that may be required for the network.

The new configuration member will be called "/net/connman/iwd"
and will be an object containing settings specific to IWD.
More settings could be added here if needed but for now only
the following are defined:

{
  send_hostname: true/false,
  hidden: true/false
}

These correspond to the following network profile settings:

[IPv4].SendHostname
[Settings].Hidden
2023-11-17 09:48:22 -06:00
James Prestwood
6a60cb5a32 dpp: use the config's SSID to process scan results
The scan result handling was fragile because it assumed the kernel
would only give results matching the requested SSID. This isn't
something we should assume so instead keep the configuration object
around until after the scan and use the target SSID to lookup the
network.
2023-11-17 09:46:06 -06:00
James Prestwood
fa14ac125e dpp: use the new config->ssid member
This is now a NULL terminated string so it can be used directly.
2023-11-17 09:44:42 -06:00
James Prestwood
00ffb056e8 dpp-util: store SSID as string, not raw buffer
Nearly every use of the ssid member first has to memcpy it to a
buffer and NULL terminate. Instead just store the ssid as a
string when creating/parsing from JSON.
2023-11-17 09:44:36 -06:00
James Prestwood
aa116ba522 dpp: check that DPP is running in station watch
This was causing unneeded WARNING prints because the DPP state
was never checked. Fix this and bail out if DPP isn't running.
2023-11-16 09:47:41 -06:00
James Prestwood
3c02f387cb dpp: scan to pick up extra frequencies when enrolling
The DPP-PKEX spec provides a very limited list of frequencies used
to discover configurators, only 3 on 2.4 and 5GHz bands. Since
configurators (at least in IWD's implementation) are only allowed
on the current operating frequency its very unlikely an enrollee
will find a configurator on these frequencies out of the entire
spectrum.

The spec does mention that the 3 default frequencies should be used
"In lieu of specific channel information obtained in a manner outside
the scope of this specification, ...". This allows the implementation
some flexibility in using a broader range of frequencies.

To increase the chances of finding a configurator shared code
enrollees will first issue a scan to determine what access points are
around, then iterate these frequencies. This is especially helpful
when the configurators are IWD-based since we know that they'll be
on the same channels as the APs in the area.
2023-11-16 09:14:32 -06:00
James Prestwood
c8a86edffe dpp: fix fragile scan/connecting logic
The post-DPP connection was never done quite right due to station's
state being unknown. The state is now tracked in DPP by a previous
patch but the scan path in DPP is still wrong.

It relies on station autoconnect logic which has the potential to
connect to a different network than what was configured with DPP.
Its unlikely but still could happen in theory. In addition the scan
was not selectively filtering results by the SSID that DPP
configured.

This fixes the above problems by first filtering the scan by the
SSID. Then setting the scan results into station without triggering
autoconnect. And finally using network_autoconnect() directly
instead of relying on station to choose the SSID.
2023-11-16 09:10:39 -06:00
James Prestwood
e2f28312e2 dpp: add station watch to DPP
DPP (both DPP and PKEX) run the risk of odd behavior if station
decides to change state. DPP is completely unaware of this and
best case would just result in a protocol failure, worst case
duplicate calls to __station_connect_network.

Add a station watch and stop DPP if station changes state during
the protocol.
2023-11-16 09:07:22 -06:00
James Prestwood
485f9f56bf dpp: remove duplicate connected network check 2023-11-16 09:07:10 -06:00
Denis Kenzior
30c6a10f28 netdev: Separate connect_failed and disconnected paths
Commit c59669a366c5 ("netdev: disambiguate between disconnection types")
introduced different paths for different types of disconnection
notifications from netdev.  Formalize this further by having
netdev_connect_failed only invoke connect_cb.

Disconnections that could be triggered outside of connection
related events are now handled on a different code path.  For this
purpose, netdev_disconnected() is introduced.
2023-11-14 17:40:56 -06:00
Denis Kenzior
a14d78596d netdev: Simplify netdev_auth_cb error logic 2023-11-14 17:29:59 -06:00
Denis Kenzior
972d277363 netdev: Remove improper use of netdev_connect_failed
When a roam event is received, iwd generates a firmware scan request and
notifies its event filter of the ROAMING condition.  In cases where the
firmware scan could not be started successfully, netdev_connect_failed
is invoked.  This is not a correct use of netev_connect_failed since it
doesn't actually disconnect the underlying netdev and the reflected
state becomes de-synchronized from the underlying kernel device.

The firmware scan request could currently fail for two reasons:
  1. nl80211 genl socket is in a bad state, or
  2. the scan context does not exist

Since both reasons are highly unlikely, simply use L_WARN instead.

The other two cases where netdev_connect_failed is used could only occur
if the kernel message is invalid.  The message is ignored in that case
and a warning is printed.

The situation described above also exists in netdev_get_fw_scan_cb. If
the scan could not be completed successfully, there's not much iwd can
do to recover.  Have iwd remain in roaming state and print an error.
2023-11-14 17:27:34 -06:00
Denis Kenzior
c59669a366 netdev: disambiguate between disconnection types
There are generally three scenarios where iwd generates a disconnection
command to the kernel:
  1. Error conditions stemming from a connection related event.  For
     example if SAE/FT/FILS authentication fails during Authenticate or
     Associate steps and the kernel doesn't disconnect properly.
  2. Deauthentication after the connection has been established and not
     related to a connection attempt in progress.  For example, SA Query
     processing that triggers an disconnect.
  3. Disconnects that are triggered due to a handshake failure or if
     setting keys resulting from the handshake fails.  These disconnects
     can be triggered as a result of a pending connection or when a
     connection has been established (e.g. due to rekeying).

Distinguish between 1 and 2/3 by having the disconnect procedure take
different paths.  For now there are no functional changes since all
paths end up in netdev_connect_failed(), but this will change in the
future.
2023-11-14 14:55:06 -06:00
Denis Kenzior
28798990d2 netdev: Move CMD_REKEY_OFFLOAD builder to nl80211util 2023-11-14 10:09:07 -06:00
Denis Kenzior
05c1d34c6e netdev: Move CMD_NEW_KEY RX-only builder to nl80211util 2023-11-14 10:03:58 -06:00
Denis Kenzior
708a8feaba netdev: Move pairwise NEW_KEY builder to nl80211util 2023-11-14 09:57:36 -06:00
Denis Kenzior
1aa83722a0 netdev: Move CMD_DEL_STATION builder to nl80211util
While here, also get rid of netdev_del_station.  The only user of this
function was in ap.c and it could easily be replaced by invoking the new
nl80211_build_del_station function.  The callback used by
netdev_build_del_station only printed an error and didn't do anything
useful.  Get rid of it for now.
2023-11-14 09:49:39 -06:00
Denis Kenzior
904373eee7 netdev: Move CMD_DEAUTHENTICATE builder to nl80211util 2023-11-14 09:26:49 -06:00
Denis Kenzior
7498eaae62 netdev: Move CMD_DISCONNECT builder to nl80211util 2023-11-14 09:21:58 -06:00
Denis Kenzior
d12d8bec85 netdev: Don't unnecessarily call netdev_connect_failed
netdev_begin_connection() already invokes netdev_connect_failed on
error.  Remove any calls to netdev_connect_failed in callers of
netdev_begin_connection().

Fixes: 4165d9414f54 ("netdev: use wiphy radio work queue for connections")
2023-11-13 23:11:12 -06:00
Denis Kenzior
afc8f53fd3 netdev: Use CMD_DISCONNECT if OCI fails
If netdev_get_oci fails, a goto deauth is invoked in order to terminate
the current connection and return an error to the caller.  Unfortunately
the deauth label builds CMD_DEAUTHENTICATE in order to terminate the
connection.  This was fine because it used to handle authentication
protocols that ran over CMD_AUTHENTICATE and CMD_ASSOCIATE.  However,
OCI can also be used on FullMAC hardware that does not support them.
Use CMD_DISCONNECT instead which works everywhere.

Fixes: 06482b811626 ("netdev: Obtain operating channel info")
2023-11-13 21:29:08 -06:00
Denis Kenzior
e1c2706674 netdev: sa_query: Fix reason code handling
The reason code field was being obtained as a uint8_t value, while it is
actually a uint16_t in little-endian byte order.

Fixes: f3cc96499c44 ("netdev: added support for SA Query")
2023-11-13 17:14:34 -06:00
Denis Kenzior
bef70275f7 netdev: Fix obtaining reason code from deauth frames
The reason code from deauthentication frame was being obtained as a
uint8_t instead of a uint16_t.  The value was only ever used in an
informational statement.  Since the value was in little endian, only the
first 8 bits of the reason code were obtained.  Fix that.

Fixes: 2bebb4bdc7ee ("netdev: Handle deauth frames prior to association")
2023-11-13 16:43:39 -06:00
James Prestwood
dbce8f9ff9 auto-t: get DPP PKEX test running reliably
Several tests do not pass due to some additional changes that have
not been merged. Remove these cases and add some hardening after
discovering some unfortunate wpa_supplicant behavior.

 - Disable p2p in wpa_supplicant. With p2p enabled an extra device
   is created which starts receiving DPP frames and printing
   confusing messages.
 - Remove extra asserts which don't make sense currently. These
   will be added back later as future additions to PKEX are
   upstreamed.
 - Work around wpa_supplicant retransmit limitation. This is
   described in detail in the comment in pkex_test.py
2023-11-13 09:47:13 -06:00
James Prestwood
13952ff350 auto-t: add stop APIs and fix some issues wpas.py
- wait_for_event was returning a list in certain cases, not the
   event itself
 - The configurator ID was not being printed (',' instead of '%')
 - The DPP ID was not being properly waited for with PKEX
2023-11-13 09:46:58 -06:00
James Prestwood
2be49a93ba auto-t: make test timeout configurable
With the addition of DPP PKEX autotests some of the timeouts are
quite long and hit test-runners maximum timeouts. For UML we should
allow this since time-travel lets us skip idle waits. Move the test
timeout out of a global define and into the argument list so QEMU
and UML can define it differently.
2023-11-13 09:46:34 -06:00
James Prestwood
3b6d279184 client: add client commands for shared code configuration
The StartConfigurator() call was left out since there would be no
functional difference to the user in iwctl. Its expected that
human users of the shared code API provide the code/id ahead of
time, i.e. use ConfigureEnrollee/StartEnrollee.
2023-11-11 10:27:27 -06:00
James Prestwood
6e2dacb0ec client: Add shared code DBus interface 2023-11-11 10:27:10 -06:00
Finn Behrens
8d2e35b2d4 client: display_completion_matches add 0-byte check
Check that enough space for newline and 0-byte is left in line.
This fixes a buffer overflow on specific completion results.

Reported-By: Leona Maroni <dev@leona.is>
2023-11-11 10:24:01 -06:00
James Prestwood
2f4c09def0 dpp: fix removed dpp_reset in Stop()
It seems in my patch reordering both stop methods lost the actual
call to dpp_reset().
2023-11-09 20:15:56 -06:00
James Prestwood
29778733e5 auto-t: add DPP PKEX tests 2023-11-09 10:35:21 -06:00
James Prestwood
6f7384d5c7 auto-t: add APIs for PKEX
Also added some sanity checks to the existing DPP APIs to make
sure started/role gets set correctly.
2023-11-09 10:35:11 -06:00
James Prestwood
809ddcebbd auto-t: add utils for wpa_supplicant PKEX 2023-11-09 10:35:00 -06:00
James Prestwood
2ca9a55fd5 dpp: Add StartConfigurator, PKEX agent support
Adds a configurator variant to be used along side an agent. When
called the configurator will start and wait for an initial PKEX
exchange message from an enrollee at which point it will request
the code from an agent. This provides more flexibility for
configurators that are capable of configuring multiple enrollees
with different identifiers/codes.

Note that the timing requirements per the DPP spec still apply
so this is not meant to be used with a human configurator but
within an automated agent which does a quick lookup of potential
identifiers/codes and can reply within the 200ms window.
2023-11-09 10:34:46 -06:00
James Prestwood
cf378e562e dpp: initial version of PKEX configurator support
The PKEX configurator role is currently limited to being a responder.
When started the configurator will listen on its current operating
channel for a PKEX exchange request. Once received it and the
encrypted key is properly decrypted it treats this peer as the
enrollee and won't allow configurations from other peers unless
PKEX is restarted. The configurator will encrypt and send its
encrypted ephemeral key in the PKEX exchange response. The enrollee
then sends its encrypted bootstrapping key (as commit-reveal request)
then the same for the configurator (as commit-reveal response).

After this, PKEX authentication begins. The enrollee is expected to
send the authenticate request, since its the initiator.
2023-11-09 10:26:59 -06:00
James Prestwood
a7d35a27a3 dpp: initial version of PKEX enrollee support
This is the initial support for PKEX enrollees acting as the
initiator. A PKEX initiator starts the protocol by broadcasting
the PKEX exchange request. This request contains a key encrypted
with the pre-shared PKEX code. If accepted the peer sends back
the exchange response with its own encrypted key. The enrollee
decrypts this and performs some crypto/hashing in order to establish
an ephemeral key used to encrypt its own boostrapping key. The
boostrapping key is encrypted and sent to the peer in the PKEX
commit-reveal request. The peer then does the same thing, encrypting
its own bootstrapping key and sending to the initiator as the
PKEX commit-reveal response.

After this, both peers have exchanged their boostrapping keys
securely and can begin DPP authentication, then configuration.

For now the enrollee will only iterate the default channel list
from the Easy Connect spec. Future upates will need to include some
way of discovering non-default channel configurators, but the
protocol needs to be ironed out first.
2023-11-09 10:23:01 -06:00
James Prestwood
9dbfac2756 doc: document Stop() correctly for both DPP interfaces
Stop() was separated more clearly between the two interfaces and will
now return NotFound if called on an interface that isn't currently
running.
2023-11-09 10:21:14 -06:00
James Prestwood
c193d36499 auto-t: fix testDPP after Stop() change
Stop() will now return NotFound if DPP is not running. This causes
the DPP test to fail since it calls this regardless if the protocol
already stopped. Ignore this exception since tests end in various
states, some stopped and some not.
2023-11-09 10:20:51 -06:00
James Prestwood
f9833665b7 dpp: introduce dpp_interface type, prep for PKEX
PKEX and DPP will share the same state machine since the DPP protocol
follows PKEX. This does pose an issue with the DBus interfaces
because we don't want DPP initiated by the SharedCode interface to
start setting properties on the DeviceProvisioning interface.

To handle this a dpp_interface enum is being introduced which binds
the dpp_sm object to a particular interface, for the life of the
protocol run. Once the protocol finishes the dpp_sm can be unbound
allowing either interface to use it again later.
2023-11-09 10:05:13 -06:00
James Prestwood
c0a356711d dpp-util: fix typo, 'REQUST' 2023-11-09 10:05:07 -06:00
Denis Kenzior
653122498a treewide: Fix compilation due to missing rtnetlink.h 2023-11-09 09:27:00 -06:00
Ronan Pigott
c574c80e27 tree-wide: correct the spelling Ghz -> GHz
This mispelling was present in the configuration, so I retained parsing
of the legacy BandModifier*Ghz options for compatibility. Without this
change anyone spelling GHz correctly in their configs would be very
confused.
2023-11-07 21:11:50 -06:00
James Prestwood
20f13184f2 doc: PKEX support for DPP
PKEX is part of the WFA EasyConnect specification and is
an additional boostrapping method (like QR codes) for
exchanging public keys between a configurator and enrollee.

PKEX operates over wifi and requires a key/code be exchanged
prior to the protocol. The key is used to encrypt the exchange
of the boostrapping information, then DPP authentication is
started immediately aftewards.

This can be useful for devices which don't have the ability to
scan a QR code, or even as a more convenient way to share
wireless credentials if the PSK is very secure (i.e. not a
human readable string).

PKEX would be used via the three DBus APIs on a new interface
SharedCodeDeviceProvisioning.

ConfigureEnrollee(a{sv}) will start a configurator with a
static shared code (optionally identifier) passed in as the
argument to this method.

StartEnrollee(a{sv}) will start a PKEX enrollee using a static
shared code (optionally identifier) passed as the argument to
the method.

StartConfigurator(o) will start a PKEX configurator and use the
agent specified by the path argument. The configurator will query
the agent for a specific code when an enrollee sends the initial
exchange message.

After the PKEX protocol is finished, DPP bootstrapping keys have
been exchanged and DPP Authentication will start, followed by
configuration.
2023-11-07 20:24:38 -06:00
James Prestwood
8864329928 netdev: handle/send beacon loss event 2023-11-07 12:15:05 -06:00
James Prestwood
e57cc5d4c6 station: start roam on beacon loss event
Beacon loss handling was removed in the past because it was
determined that this even always resulted in a disconnect. This
was short sighted and not always true. The default kernel behavior
waits for 7 lost beacons before emitting this event, then sends
either a few nullfuncs or probe requests to the BSS to determine
if its really gone. If these come back successfully the connection
will remain alive. This can give IWD some time to roam in some
cases so we should be handling this event.

Since beacon loss indicates a very poor connection the roam scan
is delayed by a few seconds in order to give the kernel a chance
to send the nullfuncs/probes or receive more beacons. This may
result in a disconnect, but it would have happened anyways.
Attempting a roam mainly handles the case when the connection can
be maintained after beacon loss, but is still poor.
2023-11-07 12:15:05 -06:00
James Prestwood
9107378efe station: provide new state in __station_connect_network
This is being done to allow the DPP module to work correctly. DPP
currently uses __station_connect_network incorrectly since it
does not (and cannot) change the state after calling. The only
way to connect with a state change is via station_connect_network
which requires a DBus method that triggered the connection; DPP
does not have this due to its potentially long run time.

To support DPP there are a few options:
 1. Pass a state into __station_connect_network (this patch)
 2. Support a NULL DBus message in station_connect_network. This
    would require several NULL checks and adding all that to only
    support DPP just didn't feel right.
 3. A 3rd connect API in station which wraps
    __station_connect_network and changes the state. And again, an
    entirely new API for only DPP felt wrong (I guess we did this
    for network_autoconnect though...)

Its about 50/50 between call sites that changed state after calling
and those that do not. Changing the state inside
__station_connect_network felt useful enough to cover the cases that
could benefit and the remaining cases could handle it easily enough:
 - network_autoconnect(), and the state is changed by station after
   calling so it more or less follows the same pattern just routes
   through network. This will now pass the CONNECTING_AUTO state
   from within network vs station.
 - The disconnect/reconnect path. Here the state is changed to
   ROAMING prior in order to avoid multiple state changes. Knowing
   this the same ROAMING state can be passed which won't trigger a
   state change.
 - Retrying after a failed BSS. The state changes on the first call
   then remains the same for each connection attempt. To support this
   the current station->state is passed to avoid a state change.
2023-11-02 20:40:07 -05:00
James Prestwood
5a78ebe895 dbus: add net.connman.iwd.SharedCodeAgent DBus interface 2023-11-02 20:31:05 -05:00
James Prestwood
c398672200 dpp: allow enrollee to be authentication initiator
Until now IWD only supported enrollees as responders (configurators
could do both). For PKEX it makes sense for the enrollee to be the
initiator because configurators in the area are already on their
operating channel and going off is inefficient. For PKEX, whoever
initiates also initiates authentication so for this reason the
authentication path is being opened up to allow enrollees to
initiate.
2023-11-02 20:30:18 -05:00
James Prestwood
b8bfbc141d dpp: fix config request header check
The check for the header was incorrect according to the spec.
Table 58 indicates that the "Query Response Info" should be set
to 0x00 for the configuration request. The frame handler was
expecting 0x7f which is the value for the config response frame.

Unfortunately wpa_supplicant also gets this wrong and uses 0x7f
in all cases which is likely why this value was set incorrectly
in IWD. The issue is that IWD's config request is correct which
means IWD<->IWD configuration is broken. (and wpa_supplicant as
a configurator likely doesn't validate the config request).

Fix this by checking both 0x7f and 0x00 to handle both
supplicants.
2023-11-02 20:28:06 -05:00
James Prestwood
a943a81f87 dpp: remove scan_periodic_stop calls
Stopping periodic scans and not restarting them prevents autoconnect
from working again if DPP (or the post-DPP connect) fails. Since
the DPP offchannel work is at a higher priority than scanning (and
since new offchannels are queue'd before canceling) there is no risk
of a scan happening during DPP so its safe to leave periodic scans
running.
2023-11-02 20:27:59 -05:00
James Prestwood
320041eaf2 station: rate limit packet loss roam scans
The packet loss handler puts a higher priority on roaming compared
to the low signal roam path. This is generally beneficial since this
event usually indicates some problem with the BSS and generally is
an indicator that a disconnect will follow sometime soon.

But by immediately issuing a scan we run the risk of causing many
successive scans if more packet loss events arrive following
the roam scans (and if no candidates are found). Logs provided
further.

To help with this handle the first event with priority and
immediately issue a roam scan. If another event comes in within a
certain timeframe (2 seconds) don't immediately scan, but instead
rearm the roam timer instead of issuing a scan. This also handles
the case of a low signal roam scan followed by a packet loss
event. Delaying the roam will at least provide some time for packets
to get out in between roam scans.

Logs were snipped to be less verbose, but this cycled happened
5 times prior. In total 7 scans were issued in 5 seconds which may
very well have been the reason for the local disconnect:

Oct 27 16:23:46 src/station.c:station_roam_failed() 9
Oct 27 16:23:46 src/wiphy.c:wiphy_radio_work_done() Work item 29 done
Oct 27 16:23:47 src/netdev.c:netdev_mlme_notify() MLME notification Notify CQM(64)
Oct 27 16:23:47 src/station.c:station_packets_lost() Packets lost event: 10
Oct 27 16:23:47 src/station.c:station_roam_scan() ifindex: 9
Oct 27 16:23:47 src/wiphy.c:wiphy_radio_work_insert() Inserting work item 30
Oct 27 16:23:47 src/wiphy.c:wiphy_radio_work_next() Starting work item 30
Oct 27 16:23:47 src/station.c:station_start_roam() Using cached neighbor report for roam
Oct 27 16:23:47 src/scan.c:scan_notify() Scan notification Trigger Scan(33)
Oct 27 16:23:47 src/scan.c:scan_request_triggered() Active scan triggered for wdev a
Oct 27 16:23:47 src/scan.c:scan_notify() Scan notification New Scan Results(34)
Oct 27 16:23:47 src/netdev.c:netdev_link_notify() event 16 on ifindex 9
... scan results ...
Oct 27 16:23:47 src/station.c:station_roam_failed() 9
Oct 27 16:23:47 src/wiphy.c:wiphy_radio_work_done() Work item 30 done
Oct 27 16:23:47 src/netdev.c:netdev_mlme_notify() MLME notification Notify CQM(64)
Oct 27 16:23:47 src/station.c:station_packets_lost() Packets lost event: 10
Oct 27 16:23:47 src/station.c:station_roam_scan() ifindex: 9
Oct 27 16:23:47 src/wiphy.c:wiphy_radio_work_insert() Inserting work item 31
Oct 27 16:23:47 src/wiphy.c:wiphy_radio_work_next() Starting work item 31
Oct 27 16:23:47 src/station.c:station_start_roam() Using cached neighbor report for roam
Oct 27 16:23:47 src/scan.c:scan_notify() Scan notification Trigger Scan(33)
Oct 27 16:23:47 src/scan.c:scan_request_triggered() Active scan triggered for wdev a
Oct 27 16:23:48 src/scan.c:scan_notify() Scan notification New Scan Results(34)
Oct 27 16:23:48 src/netdev.c:netdev_link_notify() event 16 on ifindex 9
... scan results ...
Oct 27 16:23:48 src/station.c:station_roam_failed() 9
Oct 27 16:23:48 src/wiphy.c:wiphy_radio_work_done() Work item 31 done
Oct 27 16:23:48 src/netdev.c:netdev_mlme_notify() MLME notification Notify CQM(64)
Oct 27 16:23:48 src/station.c:station_packets_lost() Packets lost event: 10
Oct 27 16:23:48 src/station.c:station_roam_scan() ifindex: 9
Oct 27 16:23:48 src/wiphy.c:wiphy_radio_work_insert() Inserting work item 32
Oct 27 16:23:48 src/wiphy.c:wiphy_radio_work_next() Starting work item 32
Oct 27 16:23:48 src/station.c:station_start_roam() Using cached neighbor report for roam
Oct 27 16:23:48 src/scan.c:scan_notify() Scan notification Trigger Scan(33)
Oct 27 16:23:48 src/scan.c:scan_request_triggered() Active scan triggered for wdev a
Oct 27 16:23:49 src/netdev.c:netdev_link_notify() event 16 on ifindex 9
Oct 27 16:23:49 src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
Oct 27 16:23:49 src/netdev.c:netdev_mlme_notify() MLME notification Deauthenticate(39)
Oct 27 16:23:49 src/netdev.c:netdev_deauthenticate_event()
Oct 27 16:23:49 src/netdev.c:netdev_mlme_notify() MLME notification Disconnect(48)
Oct 27 16:23:49 src/netdev.c:netdev_disconnect_event()
Oct 27 16:23:49 Received Deauthentication event, reason: 4, from_ap: false
2023-10-30 09:43:12 -05:00
James Prestwood
3ac5da2535 dbus: add SharedCodeDeviceProvisioning interface definition 2023-10-29 17:28:03 -05:00
James Prestwood
aabedeeb6c unit: add PKEX DPP tests 2023-10-29 17:21:28 -05:00
James Prestwood
b3071dfd15 unit: add DPP test for mutual authentication 2023-10-29 17:19:43 -05:00
James Prestwood
5b49ea4e2d unit: make test-dpp key derivation test more extendable
Use a new structure to hold key values so they can be changed for
different test vectors while using the same test function.
2023-10-29 17:17:55 -05:00
James Prestwood
acb1abceae dpp: support mutual authentication
This will be needed for PKEX support. It requires an additional
value, L, be derived and used in some of the hashing functions.
2023-10-29 17:17:21 -05:00
James Prestwood
2f2798afb8 dpp-util: add crypto for PKEX 2023-10-29 17:08:08 -05:00
James Prestwood
0859ed8448 dpp: make the protocol timeout more flexible
Include a specific timeout value so different protocols can specify
different timeouts. For example once the authentication timeout
should not take very long (even 10 seconds seems excessive) but
adding PKEX may warrant longer timeouts.

For example discovering a configurator IWD may want to wait several
minutes before ending the discovery. Similarly running PKEX as a
configurator we should put a hard limit on the time, but again
minutes rather than 10 seconds.
2023-10-29 17:05:35 -05:00
James Prestwood
efdc2a63eb dpp: check configurator role in config request frame
We shouldn't ever get this frame as an enrollee, so disregard
2023-10-29 17:05:10 -05:00
James Prestwood
3e0e31544e unit: correct memcpy overrun in test-dpp
The memcpy in HEX2BUF was copying the length of the buffer that was
passed in, not the actual length of the converted hexstring. This
test was segfaulting in the Alpine CI which uses clang/musl.
2023-10-26 09:32:30 -05:00
James Prestwood
49b9eae18c offchannel: handle out of order ACKs/events
Its been seen (so far only in mac80211_hwsim + UML) where an
offchannel requests ACK comes after the ROC started event. This
causes the ROC started event to never call back to notify since
info->roc_cookie is unset and it appears to be coming from an
external process.

We can detect this situation in the ROC notify event by checking
if there is a pending ROC command and if info->roc_cookie does
not match. This can also be true for an external event so we just
set a new "early_cookie" member and return.

Then, when the ACK comes in for the ROC request, we can validate
if the prior event was associated with IWD or some external
process. If it was from IWD call the started callback, otherwise
the ROC notify event should come later and handled under the
normal logic where the cookies match.
2023-10-26 09:30:03 -05:00
James Prestwood
0a502562c3 offchannel: Use roc id in offchannel_cancel lookup
Instead of looking up by wdev, lookup by the ID itself. We
shouldn't ever have more than one info per wdev in the queue but
looking up the _exact_ info structure doesn't hurt in case things
change in the future.
2023-10-24 21:21:36 -05:00
James Prestwood
ef27f87dbe station: reload settings in 'netconfig_after_roam' case
If netconfig is canceled before completion (when roaming) the
settings are freed and never loaded again once netconfig is started
post-roam. Now after a roam make sure to re-load the settings and
start netconfig.
2023-10-20 10:25:44 -05:00
James Prestwood
ccb29663cc station: fix unintended netconfig_reset pre-roaming
Commit 23f0f5717c did not correctly handle the reassociation
case where the state is set from within station_try_next_transition.
If IWD reassociates netconfig will get reset and DHCP will need to
be done over again after the roam. Instead get the state ahead of
station_try_next_transition.

Fixes: 23f0f5717ca0 ("station: allow roaming before netconfig finishes")
2023-10-20 10:23:17 -05:00
James Prestwood
2c7bf2756e unit: update test-dpp with API changes 2023-10-19 09:33:41 -05:00
James Prestwood
c0b92d9498 dpp-util: allow mutual auth in dpp_derive_ke
The Ke derivation requires an additional "L.x" value when
mutual authentication is used.
2023-10-19 09:33:24 -05:00
James Prestwood
808f8eea34 dpp-util: allow for mutual authentication in i/r_auth
When using mutual authentication an additional value needs to
be hashed when deriving i/r_auth values. A NULL value indicates
no mutual authentication (zero length iovec is passed to hash).
2023-10-19 09:25:35 -05:00
James Prestwood
0c9df85f5e dpp: fix retransmits if on operating channel
DPP configurators are running the majority of the protocol on the
current operating channel, meaning no ROC work. The retry logic
was bailing out if !dpp->roc_started with the assumption that DPP
was in between requesting offchannel work and it actually starting.
For configurators, this may not be the case. The offchannel ID also
needs to be checked, and if no work is scheduled we can send the
frame.
2023-10-17 10:35:13 -05:00
James Prestwood
30effaf164 dpp: move/store max_roc setting into dpp_create
This value won't change since its per-phy so initialize it
when creating the DPP state machine rather than every time
DPP is started.
2023-10-17 10:31:32 -05:00
James Prestwood
33ba7f7dcd dpp: rename dpp_presence_timeout to be generic
PKEX will utilize the same offchannel timeout, so rename to
dpp_offchannel_timeout to be more generic.
2023-10-17 10:30:47 -05:00
James Prestwood
d0c1025179 dpp: rename auth_addr to peer_addr
This is more generic and with adding PKEX it makes sense to
refer to it as peer_addr.
2023-10-17 10:20:50 -05:00
James Prestwood
fe9751d4d8 dpp-util: fix typo "COMMIT_REVEAP_RESPONSE" 2023-10-17 10:18:49 -05:00
James Prestwood
6320d6db0f crypto: remove label from prf_plus, instead use va_args
The prf_plus API was a bit restrictive because it only took a
string label which isn't compatible with some specs (e.g. DPP
inputs to HKDF-Expand). In addition it took additional label
aruments which were appended to the HMAC call (and the
non-intuitive '\0' if there were extra arguments).

Instead the label argument has been removed and callers can pass
it in through va_args. This also lets the caller decided the length
and can include the '\0' or not, dependent on the spec the caller
is following.
2023-10-17 10:13:42 -05:00
James Prestwood
96587f3c8c iwmon: print HE capabilities element
Adds a handler for the HE capabilities element and reworks the way
the MCS/NSS support bits are printed.

Now if the MCS support is 3 (unsupported) it won't be printed. This
makes the logs a bit shorter to read.
2023-10-16 13:22:07 -05:00
Sertonix Norson
f780f73f75 test: log correct function name
Matched the printed function name with the actual function name.

The simple-agent test prints the function name to allow easier debugging.

One name was not set currectly (most likely through copy pasting).
2023-10-16 13:20:33 -05:00
James Prestwood
dfb76edda8 sae: fix usage of compressed points (after ELL is fixed)
SAE was also relying on the ELL bug which was incorrectly performing
a subtraction on the Y coordinate based on the compressed point type.
Correct this and make the point type more clear (rather than
something like "is_odd + 2").
2023-10-11 10:19:42 -05:00
James Prestwood
06ad1ace00 eap-pwd: fix usage of compressed points (after ELL is fixed)
EAP-PWD was incorrectly computing the PWE but due to the also
incorrect logic in ELL the point converted correctly. This is
being fixed, so both places need the reverse logic.

Also added a big comment explaining why this is, and how
l_ecc_point_from_data behaves since its somewhat confusing since
EAP-PWD expects the pwd-seed to be compared to the actual Y
coordinate (which is handled automatically by ELL).
2023-10-11 10:19:34 -05:00
James Prestwood
2ba88f05e9 dpp-util: fix incorrect ASN1 compressed public key encoding
The prefix to the X coordinate was incorrect when using compressed
points. This has been modified to match the ANSI X9.62 spec.
2023-10-11 10:19:24 -05:00
James Prestwood
b7180d4d29 unit: add to test-dpp to expose ASN1 point conversion bug
Add a test to show the incorrect ASN1 conversion to and from points.
This was due to the check if Y is odd/even being inverted which
incorrectly prefixes the X coordinate with the wrong byte.

The test itself was not fully correct because it was using compliant
points rather than full points, and the spec contains the entire
Y coordinate so the full point should be used.

This patch also adds ASN1 conversions to validate that
dpp_point_from_asn1 and dpp_point_to_asn1 work properly.
2023-10-11 09:58:31 -05:00
Denis Kenzior
600bea73ec crypto: use SWAP from useful.h 2023-10-11 09:58:31 -05:00
Denis Kenzior
f86e7283e7 eap: Silence warning
The previous attempt at working around this warning seems to no longer
work with gcc 13

In function ‘eap_handle_response’,
    inlined from ‘eap_rx_packet’ at src/eap.c:570:3:
src/eap.c:421:49: error: ‘vendor_id’ may be used uninitialized [-Werror=maybe-uninitialized]
  421 |         (type == EAP_TYPE_EXPANDED && vendor_id == (id) && vendor_type == (t))
      |                                       ~~~~~~~~~~^~~~~~~
src/eap.c:533:20: note: in expansion of macro ‘IS_EXPANDED_RESPONSE’
  533 |         } else if (IS_EXPANDED_RESPONSE(our_vendor_id, our_vendor_type))
      |                    ^~~~~~~~~~~~~~~~~~~~
src/eap.c: In function ‘eap_rx_packet’:
src/eap.c:431:18: note: ‘vendor_id’ was declared here
  431 |         uint32_t vendor_id;
      |                  ^~~~~~~~~
2023-10-06 23:24:25 -05:00
Denis Kenzior
073292315f band: Silence warning
width must be initialized since it depends on best not being NULL.  If
best passes the non-NULL check above, then width must be initialized
since both width and best are set at the same time.
2023-10-06 23:21:48 -05:00
James Prestwood
0cb3e4af30 station: check disabled band configuration in station_init
For IWD to work correctly either 2.4GHz or 5GHz bands must be enabled
(even for 6GHz to work). Check this and don't allow IWD to initialize
if both 2.4 and 5GHz is disabled.
2023-10-03 11:32:44 -05:00
Denis Kenzior
66f47343d9 wiphy: Remove unused wiphy_supports_adhoc_rsn() 2023-09-30 17:21:30 -05:00
Denis Kenzior
6e5df64f6d wiphy: Remove unused wiphy_can_offchannel_tx() 2023-09-30 17:20:29 -05:00
Denis Kenzior
71c125193f wiphy: Remove unused wiphy_get_permanent_address() 2023-09-30 17:19:22 -05:00
James Prestwood
c972684e1a wiphy: remove wiphy_get_allowed_freqs
This was recently added but with the modifications to
wiphy_band_is_disabled() its no longer needed.
2023-09-29 21:57:08 -05:00
James Prestwood
06ed56e78f scan: remove use of wiphy_get_allowed_freqs to optimize 6ghz path
wiphy_get_allowed_freqs was only being used to see if 6GHz was disabled
or not. This is expensive and requires several allocations when there
already exists wiphy_is_band_disabled(). The prior patch modified
wiphy_is_band_disabled() to return -ENOTSUP which allows scan.c to
completely remove the need for wiphy_get_allowed_freqs.

scan_wiphy_watch was also slightly re-ordered to avoid allocating
freqs_6ghz if the scan request was being completed.
2023-09-29 21:39:58 -05:00
James Prestwood
970d23a858 wiphy: make wiphy_band_is_disabled return more descriptive
The function wiphy_band_is_disabled() return was a bit misleading
because if the band was not supported it would return true which
could be misunderstood as the band is supported, but disabled.
There was only one call site and because of this behavior
wiphy_band_is_disabled needed to be paired with checking if the
band was supported.

To be more descriptive to the caller, wiphy_band_is_disabled() now
returns an int and if the band isn't supported -ENOTSUP will be
returned, otherwise 1 is returned if the band is disabled and 0
otherwise.
2023-09-29 21:32:45 -05:00
James Prestwood
0bb99bcc33 doc: document disabling bands with a 0.0 modifier 2023-09-29 10:19:03 -05:00
James Prestwood
52c098ea74 station: support user-disabled bands
This adds support to allow users to disable entire bands, preventing
scanning and connecting on those frequencies. If the
[Rank].BandModifier* options are set to 0.0 it will imply those
bands should not be used for scanning, connecting or roaming. This
now applies to autoconnect, quick, hidden, roam, and dbus scans.

This is a station only feature meaning other modules like RRM, DPP,
WSC or P2P may still utilize those bands. Trying to limit bands in
those modules may sometimes conflict with the spec which is why it
was not added there. In addition modules like DPP/WSC are only used
in limited capacity for connecting so there is little benefit gained
to disallowing those bands.
2023-09-29 10:11:40 -05:00
James Prestwood
e83070e074 scan: filter user-disabled bands for periodic scans.
To support user-disabled bands periodic scans need to specify a
frequency list filtered by any bands that are disabled. This was
needed in scan.c since periodic scans don't provide a frequency
list in the scan request.

If no bands are disabled the allowed freqs API should still
result in the same scan behavior as if a frequency list is left
out i.e. IWD just filters the frequencies as opposed to the kernel.
2023-09-29 10:10:33 -05:00
James Prestwood
6463fa2561 scan: allow splitting of scans with defined frequencies
Currently the only way a scan can be split is if the request does
not specify any frequencies, implying the request should scan the
entire spectrum. This allows the scan logic to issue an extra
request if 6GHz becomes available during the 2.4 or 5GHz scans.
This restriction was somewhat arbitrary and done to let periodic
scans pick up 6GHz APs through a single scan request.

But now with the addition of allowing user-disabled bands
periodic scans will need to specify a frequency list in case a
given band has been disabled. This will break the scan splitting
code which is why this prep work is being done.

The main difference now is the original scan frequencies are
tracked with the scan request. The reason for this is so if a
request comes in with a limited set of 6GHz frequences IWD won't
end up scanning the full 6GHz spectrum later on.
2023-09-29 10:08:03 -05:00
James Prestwood
112b1de2ee wiphy: add wiphy_get_allowed_freqs
This is more or less copied from scan_get_allowed_freqs but is
going to be needed by station (basically just saves the need for
station to do the same clone/constrain sequence itself).

One slight alteration is now a band mask can be passed in which
provides more flexibility for additional filtering.
2023-09-27 14:22:13 -05:00
James Prestwood
e4fb9786c5 scan: add scan_get_band_rank_modifier
This exposes the [Rank].BandModifier* settings so other modules
can use then. Doing this will allow user-disabling of certain
bands by setting these modifier values to 0.0.
2023-09-27 14:21:28 -05:00
James Prestwood
043a050e57 doc: document [Rank].BandModifier2_4Ghz 2023-09-27 14:21:19 -05:00
James Prestwood
f5ae310eae scan: add [Rank].BandModifier2_4Ghz
Similar to the 5/6Ghz options, allow modifying the rank for 2.4Ghz
scan results.
2023-09-27 14:20:53 -05:00
James Prestwood
8285318228 unit: include frequency 7115 in test-band
The test was not including the last frequency in the 6ghz spectrum.
2023-09-25 09:30:32 -05:00
James Prestwood
59033bc705 wiphy: fix wiphy_contrain_freq_set skipping last channel
The loop iterating the frequency attributes list was not including
the entire channel set since it was stopping at i < band->freqs_len.
The freq_attrs array is allocated to include the last channel:

band->freq_attrs = l_new(struct band_freq_attrs, num_channels + 1);
band->freqs_len = num_channels;

So instead the for loop should use i <= band->freqs_len. (I also
changed this to start the loop at 1 since channel zero is invalid).
2023-09-25 09:30:26 -05:00
James Prestwood
9205308c47 auto-t: add fallback to reassociate test 2023-09-01 23:01:14 -05:00
James Prestwood
e74dd446fb station: fall back to reassociation under certain FT failures
The auth/action status is now tracked in ft.c. If an AP rejects the
FT attempt with "Invalid PMKID" we can now assume this AP is either
mis-configured for FT or is lagging behind getting the proper keys
from neighboring APs (e.g. was just rebooted).

If we see this condition IWD can now fall back to reassociation in
an attempt to still roam to the best candidate. The fallback decision
is still rank based: if a BSS fails FT it is marked as such, its
ranking is reset removing the FT factor and it is inserted back
into the queue.

The motivation behind this isn't necessarily to always force a roam,
but instead to handle two cases where IWD can either make a bad roam
decision or get 'stuck' and never roam:

  1. If there is one good roam candidate and other bad ones. For
     example say BSS A is experiencing this FT key pull issue:
         Current BSS: -85dbm
         BSS A:       -55dbm
         BSS B:       -80dbm
     The current logic would fail A, and roam to B. In this case
     reassociation would have likely succeeded so it makes more sense
     to reassociate to A as a fallback.

  2. If there is only one candidate, but its failing FT. IWD will
     never try anything other than FT and repeatedly fail.

Both of the above have been seen on real network deployments and
result in either poor performance (1) or eventually lead to a full
disconnect due to never roaming (2).
2023-09-01 22:56:25 -05:00
James Prestwood
0007699677 ft: track FT auth/action response status
Certain return codes, though failures, can indicate that the AP is
just confused or booting up and treating it as a full failure may
not be the best route.

For example in some production deployments if an AP is rebooted it
may take some time for neighboring APs to exchange keys for
current associations. If a client roams during that time it will
reject saying the PMKID is invalid.

Use the ft_associate call return to communicate the status (if any)
that was in the auth/action response. If there was a parsing error
or no response -ENOENT is still returned.
2023-09-01 22:49:21 -05:00
James Prestwood
927e27b8b5 auto-t: Update tests to use hostapd.default() 2023-08-30 20:41:25 -05:00
James Prestwood
df4d0eef5c auto-t: require a complete hostapd default config
In many tests the hostapd configuration does not include all the
values that a test uses. Its expected that each individual test
will add the values required. In many cases its required each test
slightly alter the configuration for each change every other test
has to set the value back to either a default or its own setting.
This results in a ton of duplicated code mainly setting things
back to defaults.

To help with this problem the hostapd configuration is read in
initially and stored as the default. Tests can then simply call
.default() to set everything back. This significantly reduces or
completely removes a ton of set_value() calls.

This does require that each hostapd configuration file includes all
values any of the subtests will set, which is a small price for the
convenience.
2023-08-30 20:40:55 -05:00
Marcel Holtmann
a9578c5f99 Release 2.8 2023-08-24 14:58:33 +02:00
Marcel Holtmann
783319b45f build: Require at least version 0.58 when building with external ELL 2023-08-24 14:56:10 +02:00
Salahaldeen Altous
4a0a973790 doc: APRanges is deprecated (use APAddressPool instead) 2023-08-08 00:00:05 -05:00
James Prestwood
822ad91faa scan: remove unneeded debug prints
Removed several debug prints which are very verbose and provide
little to no important information.

The get_scan_{done,callback} prints are pointless since all the
parsed scan results are printed by station anyways.

Printing the BSS load is also not that useful since it doesn't
include the BSSID. If anything the BSS load should be included
when station prints out each individual BSS (along with frequency,
rank, etc).

The advertisement protocol print was just just left in there by
accident when debugging, and also provides basically no useful
information.
2023-08-07 23:59:17 -05:00
Denis Kenzior
613ad4bc32 build: Update to the new ell files 2023-07-17 22:51:50 -05:00
James Prestwood
b736f07e2e netdev: relax requirement for OWE AKM in assoc reply
Some APs don't include the RSNE in the associate reply during
the OWE exchange. This causes IWD to be incompatible since it has
a hard requirement on the AKM being included.

This relaxes the requirement for the AKM and instead warns if it
is not included.

Below is an example of an association reply without the RSN element

IEEE 802.11 Association Response, Flags: ........
     Type/Subtype: Association Response (0x0001)
     Frame Control Field: 0x1000
     .000 0000 0011 1100 = Duration: 60 microseconds
     Receiver address: 64:c4:03:88:ff:26
     Destination address: 64:c4:03:88:ff:26
     Transmitter address: fc:34:97:2b:1b:48
     Source address: fc:34:97:2b:1b:48
     BSS Id: fc:34:97:2b:1b:48
     .... .... .... 0000 = Fragment number: 0
     0001 1100 1000 .... = Sequence number: 456
IEEE 802.11 wireless LAN
     Fixed parameters (6 bytes)
     Tagged parameters (196 bytes)
         Tag: Supported Rates 6(B), 9, 12(B), 18, 24(B), 36, 48, 54, [Mbit/sec]
         Tag: RM Enabled Capabilities (5 octets)
         Tag: Extended Capabilities (11 octets)
         Ext Tag: HE Capabilities (IEEE Std 802.11ax/D3.0)
         Ext Tag: HE Operation (IEEE Std 802.11ax/D3.0)
         Ext Tag: MU EDCA Parameter Set
         Ext Tag: HE 6GHz Band Capabilities
         Ext Tag: OWE Diffie-Hellman Parameter
             Tag Number: Element ID Extension (255)
             Ext Tag length: 51
             Ext Tag Number: OWE Diffie-Hellman Parameter (32)
             Group: 384-bit random ECP group (20)
             Public Key: 14ba9d8abeb2ecd5d95e6c12491b16489d1bcc303e7a7fbd…
         Tag: Vendor Specific: Broadcom
         Tag: Vendor Specific: Microsoft Corp.: WMM/WME: Parameter Element

Reported-By: Wen Gong <quic_wgong@quicinc.com>
Tested-By: Wen Gong <quic_wgong@quicinc.com>
2023-07-14 09:09:51 -05:00
James Prestwood
7418c5fd3c hwsim: handle ADD/DEL_MAC_ADDR events
Handling these events notifies hwsim of address changes for interface
creation/removal outside the initial namespace as well as address
changes due to scanning address randomization.

Interfaces that hwsim already knows about are still handled via
nl80211. But any interfaces not known when ADD/DEL_MAC_ADDR events
come will be treated specially.

For ADD, a dummy interface object will be created and added to the
queue. This lets the frame processing match the destination address
correctly. This can happen both for scan randomization and interface
creation outside of the initial namespace.

For the DEL event we handle similarly and don't touch any interfaces
found via nl80211 (i.e. have a 'name') but need to also be careful
with the dummy interfaces that were created outside the initial
namespace. We want to keep these around but scanning MAC changes can
also delete them. This is why a reference count was added so scanning
doesn't cause a removal.

For example, the following sequence:

ADD_MAC_ADDR (interface creation)
ADD_MAC_ADDR (scanning started)
DEL_MAC_ADDR (scanning done)
2023-07-05 22:03:32 -05:00
James Prestwood
5f4f15a600 hwsim: move frame processing into a separate function
The ADD/DEL_MAC_ADDR events come through the unicast handler so
move the frame processing to a separate function so these other
events can be handled.
2023-07-05 21:52:19 -05:00
James Prestwood
cda7644557 hwsim: add ADD/DEL_MAC_ADDR events
These events are important to support both moving radios to other
namespaces, and to allow scan address randomization to work.
2023-07-05 21:52:09 -05:00
248 changed files with 14511 additions and 3257 deletions

3
.codespellrc Normal file
View File

@ -0,0 +1,3 @@
[codespell]
ignore-words-list = fils, FILS, SME, assertIn, OCE, clen, aci, ELL, sav, ths
skip = build-aux, linux, autom4te.cache, aclocal.m4, AUTHORS, libtool, configure*, *.5, ell

3
.gitignore vendored
View File

@ -66,6 +66,9 @@ unit/test-p2p
unit/test-band
unit/test-dpp
unit/test-json
unit/test-nl80211util
unit/test-pmksa
unit/test-storage
unit/cert-*.pem
unit/cert-*.csr
unit/cert-*.srl

133
ChangeLog
View File

@ -1,3 +1,136 @@
ver 3.10:
Fix issue with handling neighbor report on BSS TM request.
Fix issue with handling deauth and FT association failure.
Fix issue with handling roaming and old frequencies.
ver 3.9:
Fix issue with Access Point mode and frequency unlocking.
Fix issue with network configuration and BSS retry logic.
Fix issue with handling busy notification from Access Point.
Fix issue with handling P-192, P-224 and P-521 for SAE.
ver 3.8:
Fix issue with handling unit tests and missing kernel features.
ver 3.7:
Fix issue with handling length of EncryptedSecurity.
Fix issue with handling empty affinities lists.
Fix issue with handling survey scanning results.
Fix issue with handling duplicate values in DPP URI.
ver 3.6:
Fix issue with handling blacklisting and roaming requests.
Fix issue with handling CQM thresholds for FullMAC devices.
Add support for PMKSA when using FullMAC devices.
ver 3.5:
Add support for option to disable blacklist handling.
Add support for option to disable SAE for broken drivers.
ver 3.4:
Add support for the Test Anything Protocol.
ver 3.3:
Fix issue with handling External Authentication.
ver 3.2:
Fix issue with GCC 15 and -std=c23 build errors.
Add support for using PMKSA over SAE if available.
Add support for HighUtilization/StationCount thresholds.
Add support for disabling Multicast RX option.
ver 3.1:
Fix issue with handling OWE transition BSS selection.
Fix issue with handling oper class 136 starting frequency.
ver 3.0:
Fix issue with handling alpha2 code for United Kingdom.
Fix issue with handling empty TX/RX bitrate attributes.
Fix issue with handling RSSI polling fallback workaround.
Fix issue with handling harmless cloned information elements.
Add experimental support for External Authentication feature.
ver 2.22:
Fix issue with handling the Affinities property.
Fix issue with handling ConnectedAccessPoint signal when roaming.
ver 2.21:
Fix issue with pending scan requests after regdom update.
Fix issue with handling the rearming of the roaming timeout.
Fix issue with survey request and externally triggered scans.
Fix issue with RSSI fallback when setting CQM threshold fails.
Fix issue with FT-over-Air without offchannel support.
Add support for per station Affinities property.
ver 2.20:
Fix issue with PKEX timeout and number of frequencies used.
Fix issue with handling logic for handshake failures.
Fix issue with handling ConnectedAccessPoint signal.
ver 2.19:
Fix issue with handling flush flag for external scans.
Fix issue with handling SNR calculation in ranking.
ver 2.18:
Fix issue with handling BSS with invalid HE capabilities.
Fix issue with neighbor reports with invalid country codes.
Fix issue with EAP-TTLS Start packets with L flag set.
Add support for enabling SAE for AP mode operation.
ver 2.17:
Fix issue with handling deauthenticate on disconnect.
Fix issue with handling of rate estimation errors.
Fix issue with handling EAPOL frame listeners.
ver 2.16:
Fix issue with uninitialized variable and DPP encrypt.
Fix issue with Access Point mode and ATTR_MAC validation.
Fix issue with Access Point mode and frequency attributes.
Fix issue with P2P and handling client info description.
Fix issue with P2P and handling parsing of service info.
Fix issue with netconfig and handling domain list.
Add support for forcing a default ECC group.
ver 2.15:
Fix issue with notice events for connection timeouts.
Fix issue with reason code and deauthenticate event.
Fix issue with handling basename() functionality.
ver 2.14:
Fix issue with accepting PTK 4/4 after receiving PTK 2/4.
Fix issue with frequency limit for quick scans.
Fix issue with limiting DHCPv4 attempts.
ver 2.13:
Fix issue with handling netconfig and roaming conditions.
Fix issue with logging requirement for CMD_EXTERNAL_AUTH.
Fix issue with using OpenSSL 3.2 installations.
ver 2.12:
Fix issue with DPP extra settings not being used.
Fix issue with DPP and PRF+ handling on AARCH64.
Add support for SAE password identifiers.
ver 2.11:
Fix issue with handling iovecs with multiple IEs.
Fix issue with handling SAE password identifiers.
Fix issue with handling agent release method call.
ver 2.10:
Fix issue with buffer overflow for 32 byte SSIDs.
Fix issue with deauthentication before FT work completes.
Fix issue with power save disabling procedure.
ver 2.9:
Fix issue with handling certain FT failures.
Fix issue with handling user-disabled bands.
Fix issue with handling roam on beacon loss event.
Add support for PKEX configurator.
Add support for PKEX enrollee.
ver 2.8:
Fix issue with handling OWE AKM in association reply.
ver 2.7:
Fix issue with handling FT-8021X and SHA256 PMKID derivation.

View File

@ -63,12 +63,17 @@ ell_headers = ell/util.h \
ell/dhcp6.h \
ell/acd.h \
ell/cleanup.h \
ell/netconfig.h
ell/netconfig.h \
ell/sysctl.h \
ell/notifylist.h \
ell/minheap.h
ell_sources = ell/private.h \
ell/missing.h \
ell/util.c \
ell/test-private.h \
ell/test.c \
ell/test-dbus.c \
ell/strv.c \
ell/utf8.c \
ell/queue.c \
@ -143,7 +148,10 @@ ell_sources = ell/private.h \
ell/dhcp6-lease.c \
ell/dhcp6-transport.c \
ell/acd.c \
ell/netconfig.c
ell/netconfig.c \
ell/sysctl.c \
ell/notifylist.c \
ell/minheap.c
ell_shared = ell/useful.h ell/asn1-private.h
@ -210,7 +218,8 @@ eap_sources = src/eap.c src/eap.h src/eap-private.h \
if DAEMON
libexec_PROGRAMS += src/iwd
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
src/missing.h src/defs.h \
src/netdev.h src/netdev.c \
src/wiphy.h src/wiphy.c \
src/device.c \
@ -263,6 +272,10 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
src/dpp-util.h src/dpp-util.c \
src/json.h src/json.c \
src/dpp.c \
src/udev.c \
src/pmksa.h src/pmksa.c \
src/vendor_quirks.h \
src/vendor_quirks.c \
$(eap_sources) \
$(builtin_sources)
@ -312,7 +325,9 @@ client_iwctl_SOURCES = client/main.c \
client/wsc.c client/station.c \
client/diagnostic.c client/diagnostic.h \
client/daemon.c client/daemon.h \
client/dpp.c client/station-debug.c \
client/dpp.c client/dpp-pkex.c \
client/station-debug.c \
client/bss.c \
src/util.c src/util.h \
src/band.c src/band.h
@ -404,6 +419,7 @@ tools_hwsim_SOURCES = tools/hwsim.c src/mpdu.h \
src/storage.h src/storage.c \
src/common.h src/common.c \
src/band.h src/band.c \
src/ie.h src/ie.c \
src/crypto.h src/crypto.c
tools_hwsim_LDADD = $(ell_ldadd)
@ -426,7 +442,8 @@ unit_tests += unit/test-cmac-aes \
unit/test-ie unit/test-util unit/test-ssid-security \
unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \
unit/test-dpp unit/test-json
unit/test-dpp unit/test-json unit/test-nl80211util \
unit/test-pmksa unit/test-storage
endif
if CLIENT
@ -445,6 +462,7 @@ unit_test_eap_sim_SOURCES = unit/test-eap-sim.c \
src/eapol.h src/eapol.c \
src/eapolutil.h src/eapolutil.c \
src/handshake.h src/handshake.c \
src/pmksa.h src/pmksa.c \
src/eap.h src/eap.c src/eap-private.h \
src/util.h src/util.c \
src/simauth.h src/simauth.c \
@ -504,6 +522,7 @@ unit_test_eapol_SOURCES = unit/test-eapol.c \
src/eapol.h src/eapol.c \
src/eapolutil.h src/eapolutil.c \
src/handshake.h src/handshake.c \
src/pmksa.h src/pmksa.c \
src/eap.h src/eap.c src/eap-private.h \
src/eap-tls.c src/eap-ttls.c \
src/eap-md5.c src/util.c \
@ -534,6 +553,7 @@ unit_test_wsc_SOURCES = unit/test-wsc.c src/wscutil.h src/wscutil.c \
src/eapol.h src/eapol.c \
src/eapolutil.h src/eapolutil.c \
src/handshake.h src/handshake.c \
src/pmksa.h src/pmksa.c \
src/eap.h src/eap.c src/eap-private.h \
src/util.h src/util.c \
src/erp.h src/erp.c \
@ -552,6 +572,7 @@ unit_test_sae_SOURCES = unit/test-sae.c \
src/crypto.h src/crypto.c \
src/ie.h src/ie.c \
src/handshake.h src/handshake.c \
src/pmksa.h src/pmksa.c \
src/erp.h src/erp.c \
src/band.h src/band.c \
src/util.h src/util.c \
@ -575,6 +596,22 @@ unit_test_dpp_LDADD = $(ell_ldadd)
unit_test_json_SOURCES = unit/test-json.c src/json.h src/json.c shared/jsmn.h
unit_test_json_LDADD = $(ell_ldadd)
unit_test_nl80211util_SOURCES = unit/test-nl80211util.c \
src/nl80211util.h src/nl80211util.c \
src/band.h src/band.c \
src/ie.h src/ie.c \
src/util.h src/util.c
unit_test_nl80211util_LDADD = $(ell_ldadd)
unit_test_pmksa_SOURCES = unit/test-pmksa.c src/pmksa.c src/pmksa.h \
src/module.h src/util.h
unit_test_pmksa_LDADD = $(ell_ldadd)
unit_test_storage_SOURCES = unit/test-storage.c src/storage.c src/storage.h \
src/crypto.c src/crypto.h \
src/common.c src/common.h
unit_test_storage_LDADD = $(ell_ldadd)
endif
if CLIENT
@ -590,6 +627,9 @@ unit_test_client_SOURCES = unit/test-client.c \
unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd)
endif
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
$(top_srcdir)/build-aux/tap-driver.sh
TESTS = $(unit_tests)
EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \
@ -706,6 +746,7 @@ ell/internal: Makefile
done > $@
ell/ell.h: Makefile
$(AM_V_at)$(MKDIR_P) ell
$(AM_V_at)echo -n > $@
$(AM_V_GEN)for f in $(ell_headers) ; do \
echo "#include <$$f>" >> $@ ; \

6
TODO
View File

@ -110,7 +110,7 @@ Wireless monitor
- Subscribe to all nl80211 multicast groups at startup
It seems the nlmon packets are limited to actual subscribed mutlicast
It seems the nlmon packets are limited to actual subscribed multicast
groups. To get a complete picture of all the nl80211 commands and
events, it is required that iwmon adds membership to all multicast
groups that the nl80211 lists.
@ -234,7 +234,7 @@ Wireless daemon
- Implement Enrollee Session Overlap Detection after WSC Protocol Run
WSC Best Practices v2.0.1, Section 3.15 describes an enhacement to detect
WSC Best Practices v2.0.1, Section 3.15 describes an enhancement to detect
PBC session overlaps. The Enrollee is asked to perform an extra scan without
the PBC request in the ProbeRequest frames after EAP-WSC completes
successfully. If another AP in PBC mode is found, then a SessionOverlap
@ -286,7 +286,7 @@ Wireless daemon
- Support OCE mutually non-overlapping channels optimization.
OCE Section 3.10 mandates that the STA should scan channels 1, 6 and 11 in
the 2.4Ghz band first, unless it expects to find an AP on a different
the 2.4GHz band first, unless it expects to find an AP on a different
channel.
Priority: Low

View File

@ -0,0 +1,156 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import NetworkType
from hostapd import HostapdCLI
class Test(unittest.TestCase):
def initial_connection(self):
ordered_network = self.device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
self.assertFalse(self.bss_hostapd[1].list_sta())
def test_full_scan(self):
"""
Tests that IWD first tries a limited scan, then a full scan after
an AP directed roam. After the full scan yields no results IWD
should stop trying to roam.
"""
self.initial_connection()
# Disable other APs, so the scans come up empty
self.bss_hostapd[1].disable()
self.bss_hostapd[2].disable()
# Send a bad candidate list with the BSS TM request which contains a
# channel with no AP operating on it.
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
self.device.wait_for_event("roam-scan-triggered")
self.device.wait_for_event("no-roam-candidates")
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("no-roam-candidates", timeout=30)
# IWD should not trigger a roam again after the above 2 failures.
with self.assertRaises(TimeoutError):
self.device.wait_for_event("roam-scan-triggered", timeout=60)
def test_bad_candidate_list(self):
"""
Tests behavior when the AP sends a candidate list but the scan
finds no BSS's. IWD should fall back to a full scan after.
"""
self.initial_connection()
# Send a bad candidate list with the BSS TM request which contains a
# channel with no AP operating on it.
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
self.device.wait_for_event("roam-scan-triggered")
self.device.wait_for_event("no-roam-candidates")
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def test_bad_neighbor_report(self):
"""
Tests behavior when the AP sends no candidate list. IWD should
request a neighbor report. If the limited scan yields no BSS's IWD
should fall back to a full scan.
"""
# Set a bad neighbor (channel that no AP is on) to force the limited
# roam scan to fail
self.bss_hostapd[0].set_neighbor(
self.bss_hostapd[1].bssid,
"TestAPRoam",
'%s8f000000%s%s060603000000' % (self.bss_hostapd[1].bssid.replace(':', ''), "51", "0b")
)
self.initial_connection()
self.bss_hostapd[0].send_bss_transition(self.device.address, [])
self.device.wait_for_event("roam-scan-triggered")
# The AP will have sent a neighbor report with a single BSS but on
# channel 11 which no AP is on. This should result in a limited scan
# picking up no candidates.
self.device.wait_for_event("no-roam-candidates", timeout=30)
# IWD should then trigger a full scan
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def test_ignore_candidate_list_quirk(self):
"""
Tests that IWD ignores the candidate list sent by the AP since its
OUI indicates it should be ignored.
"""
# Set the OUI so the candidate list should be ignored
for hapd in self.bss_hostapd:
hapd.set_value('vendor_elements', 'dd0400180a01')
self.initial_connection()
# Send with a candidate list (should be ignored)
self.bss_hostapd[0].send_bss_transition(
self.device.address,
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
)
# IWD should ignore the list and trigger a full scan since we have not
# set any neighbors
self.device.wait_for_event("full-roam-scan")
self.device.wait_for_event("roaming", timeout=30)
self.device.wait_for_event("connected")
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
for hapd in self.bss_hostapd:
hapd.reload()
@classmethod
def setUpClass(cls):
IWD.copy_to_storage('TestAPRoam.psk')
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ]
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -11,52 +11,58 @@ from iwd import NetworkType
from hostapd import HostapdCLI
class Test(unittest.TestCase):
def validate(self, expect_roam=True):
wd = IWD()
devices = wd.list_devices(1)
device = devices[0]
ordered_network = device.get_ordered_network('TestAPRoam')
def initial_connection(self):
ordered_network = self.device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
device.connect_bssid(self.bss_hostapd[0].bssid)
self.device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
self.wd.wait_for_object_condition(self.device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
self.assertFalse(self.bss_hostapd[1].list_sta())
self.bss_hostapd[0].send_bss_transition(device.address,
[(self.bss_hostapd[1].bssid, '8f0000005102060603000000')],
def validate_roam(self, from_bss, to_bss, expect_roam=True):
from_bss.send_bss_transition(self.device.address,
self.neighbor_list,
disassoc_imminent=expect_roam)
if expect_roam:
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_change(device, from_condition, to_condition)
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
to_bss.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
else:
device.wait_for_event("no-roam-candidates")
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.wait_for_event("no-roam-candidates")
def test_disassoc_imminent(self):
self.validate(expect_roam=True)
self.initial_connection()
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
def test_no_candidates(self):
self.validate(expect_roam=False)
self.initial_connection()
# We now have BSS0 roam blacklisted
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
# Try and trigger another roam back, which shouldn't happen since now
# both BSS's are roam blacklisted
self.validate_roam(self.bss_hostapd[1], self.bss_hostapd[0], expect_roam=False)
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
@classmethod
def setUpClass(cls):
@ -65,6 +71,10 @@ class Test(unittest.TestCase):
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ]
cls.neighbor_list = [
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
]
@classmethod
def tearDownClass(cls):

View File

@ -1,5 +1,7 @@
[SETUP]
num_radios=4
hwsim_medium=true
start_iwd=false
[HOSTAPD]
rad0=ssid1.conf

View File

@ -0,0 +1,6 @@
[General]
RoamThreshold=-72
CriticalRoamThreshold=-72
[Blacklist]
InitialAccessPointBusyTimeout=20

View File

@ -0,0 +1,183 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD, IWD_CONFIG_DIR
from iwd import NetworkType
from hostapd import HostapdCLI
from hwsim import Hwsim
class Test(unittest.TestCase):
def validate_connected(self, hostapd):
ordered_network = self.device.get_ordered_network('TestAPRoam')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
self.device.connect_bssid(hostapd.bssid)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
hostapd.wait_for_event('AP-STA-CONNECTED')
def validate_ap_roamed(self, from_hostapd, to_hostapd):
from_hostapd.send_bss_transition(
self.device.address, self.neighbor_list, disassoc_imminent=True
)
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
to_hostapd.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
self.device.wait_for_event("ap-roam-blacklist-added")
def test_roam_to_optimal_candidates(self):
# In this test IWD will naturally transition down the list after each
# BSS gets roam blacklisted. All BSS's are above the RSSI thresholds.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -6500
self.rule_ssid3.signal = -6900
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam to BSS1
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# AP directed roam to BSS2
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[2])
def test_avoiding_under_threshold_bss(self):
# In this test IWD will blacklist BSS0, then roam the BSS1. BSS1 will
# then tell IWD to roam, but it should go back to BSS0 since the only
# non-blacklisted BSS is under the roam threshold.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -6500
self.rule_ssid3.signal = -7300
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam to BSS1
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# AP directed roam, but IWD should choose BSS0 since BSS2 is -73dB
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[0])
def test_connect_to_roam_blacklisted_bss(self):
# In this test a BSS will be roam blacklisted, but all other options are
# below the RSSI threshold so IWD should roam back to the blacklisted
# BSS.
self.rule_ssid1.signal = -5000
self.rule_ssid2.signal = -8000
self.rule_ssid3.signal = -8500
# Connect to BSS0
self.validate_connected(self.bss_hostapd[0])
# AP directed roam, should connect to BSS1 as its the next best
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
# Connected to BSS1, but the signal is bad, so IWD should try to roam
# again. BSS0 is still blacklisted, but its the only reasonable option
# since both BSS1 and BSS2 are below the set RSSI threshold (-72dB)
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
# IWD should have connected to BSS0, even though its roam blacklisted
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
def test_blacklist_during_roam_scan(self):
# Tests that an AP roam request mid-roam results in the AP still being
# blacklisted even though the request itself doesn't directly trigger
# a roam.
self.rule_ssid1.signal = -7300
self.rule_ssid2.signal = -7500
self.rule_ssid3.signal = -8500
# Connect to BSS0 under the roam threshold so IWD will immediately try
# roaming elsewhere
self.validate_connected(self.bss_hostapd[0])
self.device.wait_for_event("roam-scan-triggered")
self.bss_hostapd[0].send_bss_transition(
self.device.address, self.neighbor_list, disassoc_imminent=True
)
self.device.wait_for_event("ap-roam-blacklist-added")
# BSS0 should have gotten blacklisted even though IWD was mid-roam,
# causing IWD to choose BSS1 when it gets is results.
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
def setUp(self):
self.wd = IWD(True)
devices = self.wd.list_devices(1)
self.device = devices[0]
def tearDown(self):
self.wd = None
self.device = None
@classmethod
def setUpClass(cls):
IWD.copy_to_storage("main.conf.roaming", IWD_CONFIG_DIR, "main.conf")
IWD.copy_to_storage('TestAPRoam.psk')
hwsim = Hwsim()
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
HostapdCLI(config='ssid2.conf'),
HostapdCLI(config='ssid3.conf') ]
HostapdCLI.group_neighbors(*cls.bss_hostapd)
rad0 = hwsim.get_radio('rad0')
rad1 = hwsim.get_radio('rad1')
rad2 = hwsim.get_radio('rad2')
cls.neighbor_list = [
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
(cls.bss_hostapd[2].bssid, "8f0000005103060603000000"),
]
cls.rule_ssid1 = hwsim.rules.create()
cls.rule_ssid1.source = rad0.addresses[0]
cls.rule_ssid1.bidirectional = True
cls.rule_ssid1.enabled = True
cls.rule_ssid2 = hwsim.rules.create()
cls.rule_ssid2.source = rad1.addresses[0]
cls.rule_ssid2.bidirectional = True
cls.rule_ssid2.enabled = True
cls.rule_ssid3 = hwsim.rules.create()
cls.rule_ssid3.source = rad2.addresses[0]
cls.rule_ssid3.bidirectional = True
cls.rule_ssid3.enabled = True
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,2 @@
[Security]
Passphrase=EasilyGuessedPassword

View File

@ -0,0 +1,41 @@
hw_mode=g
channel=1
ssid=TestFT
utf8_ssid=1
ctrl_interface=/var/run/hostapd
r1_key_holder=120000000001
nas_identifier=dummy1
wpa=2
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
# time but we want to force FT
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=0
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
# Allow PMK cache to be shared opportunistically among configured interfaces
# and BSSes (i.e., all configurations within a single hostapd process).
okc=1
mobility_domain=1234
reassociation_deadline=60000
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
# Push mode only needed for 8021x, not PSK mode since msk already known
pmk_r1_push=0
# Allow locally generated FT response so we don't have to configure push/pull
# between BSSes running as separate hostapd processes as in the test-runner
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -0,0 +1,41 @@
hw_mode=g
channel=2
ssid=TestFT
utf8_ssid=1
ctrl_interface=/var/run/hostapd
r1_key_holder=120000000002
nas_identifier=dummy2
wpa=2
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
# time but we want to force FT
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=0
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
# Allow PMK cache to be shared opportunistically among configured interfaces
# and BSSes (i.e., all configurations within a single hostapd process).
okc=1
mobility_domain=1234
reassociation_deadline=60000
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
# Push mode only needed for 8021x, not PSK mode since msk already known
pmk_r1_push=0
# Allow locally generated FT response so we don't have to configure push/pull
# between BSSes running as separate hostapd processes as in the test-runner
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -0,0 +1,8 @@
[SETUP]
num_radios=3
start_iwd=0
hwsim_medium=yes
[HOSTAPD]
rad0=ft-psk-ccmp-1.conf
rad1=ft-psk-ccmp-2.conf

View File

@ -0,0 +1,5 @@
[Scan]
DisableMacAddressRandomization=true
[General]
RoamRetryInterval=1

View File

@ -0,0 +1,216 @@
#! /usr/bin/python3
import unittest
import sys, os
import dbus
sys.path.append('../util')
from config import ctx
import iwd
from iwd import IWD, IWDDBusAbstract
from iwd import NetworkType
from hwsim import Hwsim
from hostapd import HostapdCLI
#
# Separate client used to test DBus disconnects so we don't bring down the
# entire IWD python library
#
class AffinityClient(IWDDBusAbstract):
def __init__(self, device_path):
self._bus = dbus.bus.BusConnection(address_or_type=ctx.dbus_address)
self._station_prop_if = dbus.Interface(
self._bus.get_object(iwd.IWD_SERVICE, device_path),
iwd.DBUS_PROPERTIES)
def set(self, values):
self._station_prop_if.Set(iwd.IWD_STATION_INTERFACE, 'Affinities', dbus.Array([dbus.ObjectPath(v) for v in values], signature="o"))
def close(self):
self._bus.close()
class Test(unittest.TestCase):
def connect(self, device, hapd):
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
device.connect_bssid(hapd.bssid)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(device, condition)
def test_set_affinity(self):
device = self.wd.list_devices(1)[0]
self.connect(device, self.bss_hostapd[0])
print(device.connected_bss)
device.affinities = [device.connected_bss]
# IWD should not attempt to roam
with self.assertRaises(TimeoutError):
device.wait_for_event("roam-scan-triggered")
device.affinities = []
device.wait_for_event("roam-scan-triggered")
def test_roam_below_critical(self):
device = self.wd.list_devices(1)[0]
self.connect(device, self.bss_hostapd[0])
device.affinities = [device.connected_bss]
# IWD should not attempt to roam
with self.assertRaises(TimeoutError):
device.wait_for_event("roam-scan-triggered")
# Lower signal past critical level
self.bss0_rule.signal = -9000
device.wait_for_event("roam-scan-triggered")
def test_error_conditions(self):
device = self.wd.list_devices(1)[0]
# Calling set while disconnected should fail
with self.assertRaises(iwd.NotConnectedEx):
device.affinities = ["/some/path"]
self.connect(device, self.bss_hostapd[0])
device.affinities = [device.connected_bss]
# An invalid path should fail
with self.assertRaises(iwd.InvalidArgumentsEx):
device.affinities = [device.connected_bss, "/an/invalid/path"]
def test_affinity_client_disconnect(self):
device = self.wd.list_devices(1)[0]
client = AffinityClient(device.device_path)
self.connect(device, self.bss_hostapd[0])
client.set([device.connected_bss])
with self.assertRaises(TimeoutError):
device.wait_for_event("roam-scan-triggered")
client._bus.close()
device.wait_for_event("roam-scan-triggered")
def test_affinity_client_reconnect_during_roam(self):
device = self.wd.list_devices(1)[0]
client = AffinityClient(device.device_path)
self.connect(device, self.bss_hostapd[0])
client.set([device.connected_bss])
# Lower signal past critical level
self.bss0_rule.signal = -9000
device.wait_for_event("roam-scan-triggered")
client.close()
del client
client = AffinityClient(device.device_path)
# setting here should get cleared after connecting
client.set([device.connected_bss])
device.wait_for_event("ft-authenticating")
device.wait_for_event("associating")
device.wait_for_event("connected")
# Affinity should be reset, and IWD should be trying to roam
device.wait_for_event("roam-scan-triggered")
def test_cleanup_with_connected_client(self):
device = self.wd.list_devices(1)[0]
client = AffinityClient(device.device_path)
self.connect(device, self.bss_hostapd[0])
client.set([device.connected_bss])
self.wd.stop()
def test_affinity_removed_after_roam(self):
device = self.wd.list_devices(1)[0]
self.connect(device, self.bss_hostapd[0])
device.affinities = [device.connected_bss]
# Lower signal past critical level
self.bss0_rule.signal = -9000
device.wait_for_event("roam-scan-triggered")
device.wait_for_event("ft-authenticating")
device.wait_for_event("associating")
device.wait_for_event("connected")
self.assertEqual(device.affinities, [])
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
self.wd.stop()
self.wd = None
def setUp(self):
self.bss0_rule.signal = -8000
self.bss1_rule.signal = -8000
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
rad0 = hwsim.get_radio('rad0')
rad1 = hwsim.get_radio('rad1')
cls.bss0_rule = hwsim.rules.create()
cls.bss0_rule.source = rad0.addresses[0]
cls.bss0_rule.bidirectional = True
cls.bss0_rule.signal = -8000
cls.bss0_rule.enabled = True
cls.bss1_rule = hwsim.rules.create()
cls.bss1_rule.source = rad1.addresses[0]
cls.bss1_rule.bidirectional = True
cls.bss1_rule.signal = -8000
cls.bss1_rule.enabled = True
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None
cls.bss0_rule.remove()
cls.bss1_rule.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -260,12 +260,69 @@ class Test(unittest.TestCase):
self.wd.unregister_psk_agent(psk_agent)
def test_blacklist_disabled(self):
wd = self.wd
bss_hostapd = self.bss_hostapd
rule0 = self.rule0
rule1 = self.rule1
rule2 = self.rule2
psk_agent = PSKAgent(["secret123", 'secret123'])
wd.register_psk_agent(psk_agent)
devices = wd.list_devices(1)
device = devices[0]
rule0.drop = True
rule0.enabled = True
device.autoconnect = True
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
ordered_network = device.get_ordered_network("TestBlacklist", full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
# The first BSS should fail, and we should connect to the second. This
# should not result in a connection blacklist though since its disabled.
bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
device.disconnect()
rule0.drop = False
device.autoconnect = True
# Verify the first BSS wasn't blacklisted.
bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
def setUp(self):
_, _, name = self.id().split(".")
# TODO: If we have this pattern elsewhere it might be nice to turn this
# into a decorator e.g.
#
# @config("main.conf.disabled")
# @profile("TestBlacklist.psk")
# def test_blacklist_disabled(self)
# ...
#
if name == "test_blacklist_disabled":
IWD.copy_to_storage("main.conf.disabled", IWD_CONFIG_DIR, "main.conf")
IWD.copy_to_storage("TestBlacklist.psk")
else:
IWD.copy_to_storage("main.conf.default", IWD_CONFIG_DIR, "main.conf")
self.wd = IWD(True)
def tearDown(self):
IWD.clear_storage()
self.wd = None
self.rule0.drop = False
self.rule1.drop = False
self.rule2.drop = False
@classmethod
def setUpClass(cls):

View File

@ -0,0 +1,2 @@
[Blacklist]
InitialTimeout=0

View File

@ -0,0 +1,98 @@
#! /usr/bin/python3
import unittest
import sys, os
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hwsim import Hwsim
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def test_bss_unregister(self):
device = self.wd.list_devices(1)[0]
ordered_network = device.get_ordered_network('ssidTKIP', full_scan=True)
network = ordered_network.network_object
self.assertEqual(len(network.extended_service_set), 2)
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
self.assertIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
self.rule_bss1.enabled = True
# Even with flushing, the kernel still seems to return the scan
# results
self.wd.wait(40)
ordered_network = device.get_ordered_network('ssidTKIP', full_scan=True)
network = ordered_network.network_object
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
self.assertNotIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
self.rule_bss0.enabled = True
self.wd.wait(40)
ordered_networks = device.get_ordered_networks('ssidTKIP', full_scan=True)
self.assertIsNone(ordered_networks)
self.rule_bss0.enabled = False
ordered_networks = device.get_ordered_networks('ssidTKIP', full_scan=True)
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
self.assertNotIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
def tearDown(self):
self.rule_bss0.enabled = False
self.rule_bss1.enabled = False
self.wd.stop()
self.wd.wait(10)
self.wd = None
def setUp(self):
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
IWD.copy_to_storage('ssidTKIP.psk')
cls.bss_hostapd = [ HostapdCLI(config='ssidTKIP-1.conf'),
HostapdCLI(config='ssidTKIP-2.conf') ]
rad0 = hwsim.get_radio('rad0')
rad1 = hwsim.get_radio('rad1')
cls.rule_bss0 = hwsim.rules.create()
cls.rule_bss0.source = rad0.addresses[0]
cls.rule_bss0.bidirectional = True
cls.rule_bss0.drop = True
cls.rule_bss1 = hwsim.rules.create()
cls.rule_bss1.source = rad1.addresses[0]
cls.rule_bss1.bidirectional = True
cls.rule_bss1.drop = True
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None
cls.rule_bss0.remove()
cls.rule_bss1.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,8 @@
[SETUP]
num_radios=3
hwsim_medium=yes
start_iwd=no
[HOSTAPD]
rad0=ssidTKIP-1.conf
rad1=ssidTKIP-2.conf

View File

@ -0,0 +1,7 @@
hw_mode=g
channel=1
ssid=ssidTKIP
wpa=1
wpa_pairwise=TKIP
wpa_passphrase=secret123

View File

@ -0,0 +1,7 @@
hw_mode=g
channel=2
ssid=ssidTKIP
wpa=1
wpa_pairwise=TKIP
wpa_passphrase=secret123

View File

@ -0,0 +1,5 @@
[Security]
Passphrase=secret123
[Settings]
AutoConnect=False

View File

@ -11,7 +11,7 @@ from iwd import IWD
class Test8021xNetwork(unittest.TestCase):
'''
The bellow test cases excesise the following connection scenarios:
The below test cases excesise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -11,7 +11,7 @@ from iwd import IWD
class TestOpenNetwork(unittest.TestCase):
'''
The bellow test cases excesise the following connection scenarios:
The below test cases excesise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -11,7 +11,7 @@ from iwd import IWD
class TestWpaNetwork(unittest.TestCase):
'''
The bellow test cases exercise the following connection scenarios:
The below test cases exercise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -38,20 +38,18 @@ class Test(unittest.TestCase):
def test_iwd_as_enrollee_scan_after(self):
self.wpas.disconnect()
self.device.autoconnect = True
uri = self.device.dpp_start_enrollee()
self.wpas.dpp_configurator_create(uri)
self.wpas.dpp_configurator_start('ssidCCMP', 'secret123')
self.hapd.reload()
with self.assertRaises(Exception):
self.device.get_ordered_network('ssidCCMP', scan_if_needed=False)
self.hapd.reload()
self.hapd.wait_for_event('AP-ENABLED')
self.device.autoconnect = True
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
@ -148,8 +146,13 @@ class Test(unittest.TestCase):
self.rule0.drop = True
def tearDown(self):
self.device.disconnect()
self.device.dpp_stop()
# Tests end in various states, don't fail when tearing down.
try:
self.device.disconnect()
self.device.dpp_stop()
except:
pass
self.wpas.dpp_configurator_remove()
self.wpas.clean_up()

View File

@ -0,0 +1,2 @@
[Security]
Passphrase=IncorrectPassphrase

View File

@ -1,5 +1,5 @@
hw_mode=g
channel=1
channel=6
ssid=ssidCCMP
wpa=2

View File

@ -1,5 +1,5 @@
[SETUP]
num_radios=3
num_radios=5
start_iwd=0
hwsim_medium=yes
@ -8,3 +8,7 @@ rad0=wpas.conf
[HOSTAPD]
rad1=hostapd.conf
rad2=ssidHidden.conf
[NameSpaces]
ns0=rad3

View File

@ -0,0 +1,336 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
from iwd import IWD, SharedCodeAgent, DeviceState
from iwd import DeviceProvisioning
from wpas import Wpas
from hostapd import HostapdCLI
from hwsim import Hwsim
from config import ctx
from time import time
import os
class Test(unittest.TestCase):
def start_wpas_pkex(self, code, curve=None, **kwargs):
self.wpas.dpp_bootstrap_gen(type='pkex', curve=curve)
self.wpas.dpp_pkex_add(code=code, **kwargs)
if kwargs.get('role', 'configurator') == 'configurator':
self.wpas.dpp_configurator_create()
self.wpas.dpp_listen(2437)
def stop_wpas_pkex(self):
self.wpas.dpp_pkex_remove()
self.wpas.dpp_stop_listen()
self.wpas.dpp_configurator_remove()
def start_iwd_pkex_configurator(self, device, agent=False, profile='ssidCCMP.psk'):
self.hapd.reload()
self.hapd.wait_for_event('AP-ENABLED')
IWD.copy_to_storage(profile)
device.autoconnect = True
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(device, condition)
if agent:
self.agent = SharedCodeAgent(codes = {"test": "secret123"})
device.dpp_pkex_start_configurator(self.agent.path)
else:
device.dpp_pkex_configure_enrollee('secret123', identifier="test")
#
# WPA Supplicant has awful handling of retransmissions and no-ACK
# conditions. It only handles retransmitting the exchange request when
# there is no-ACK, which makes zero sense since its a broadcast...
#
# So, really, testing against wpa_supplicant is fragile and dependent on
# how the scheduling works out. If IWD doesn't ACK due to being on the
# next frequency or in between offchannel requests wpa_supplicant gets
# into a state where it thinks a PKEX session has been started (having
# received the exchange request) but will only accept commit-reveal
# frames. IWD is unaware because it never got a response so it keeps
# sending exchange requests which are ignored.
#
# Nevertheless we should still test against wpa_supplicant for
# compatibility so attempt to detect this case and restart the
# wpa_supplicant configurator.
#
def restart_wpas_if_needed(self):
i = 0
while i < 10:
data = self.wpas.wait_for_event("DPP-RX")
self.assertIn("type=7", data)
data = self.wpas.wait_for_event("DPP-TX")
self.assertIn("type=8", data)
data = self.wpas.wait_for_event("DPP-TX-STATUS")
if "result=no-ACK" in data:
self.stop_wpas_pkex()
self.start_wpas_pkex('secret123', identifier="test")
else:
return
i += 1
raise Exception("wpa_supplicant could not complete PKEX after 10 retries")
def test_pkex_iwd_as_enrollee(self):
self.start_wpas_pkex('secret123', identifier="test")
self.device[0].dpp_pkex_enroll('secret123', identifier="test")
self.restart_wpas_if_needed()
self.wpas.wait_for_event("DPP-AUTH-SUCCESS")
def test_pkex_iwd_as_enrollee_retransmit(self):
self.rule_reveal_req.enabled = True
self.start_wpas_pkex('secret123', identifier="test")
self.device[0].dpp_pkex_enroll('secret123', identifier="test")
self.restart_wpas_if_needed()
self.wpas.wait_for_event("DPP-AUTH-SUCCESS")
def test_pkex_unsupported_version(self):
self.start_wpas_pkex('secret123', identifier="test", version=2)
now = time()
self.device[0].dpp_pkex_enroll('secret123', identifier="test")
condition = "obj.started == False"
self.wd.wait_for_object_condition(self.device[0]._sc_device_provisioning,
condition, max_wait=125)
# Check the enrollee stopped after 2 minutes
elapsed = time() - now
self.assertLess(elapsed, 125)
def test_pkex_configurator_timeout(self):
self.start_iwd_pkex_configurator(self.device[0])
now = time()
condition = "obj.started == False"
self.wd.wait_for_object_condition(self.device[0]._sc_device_provisioning,
condition, max_wait=125)
# Check the enrollee stopped after 2 minutes
elapsed = time() - now
self.assertLess(elapsed, 125)
def test_pkex_iwd_as_configurator(self):
self.start_iwd_pkex_configurator(self.device[0])
self.start_wpas_pkex('secret123', identifier="test", initiator=True,
role='enrollee')
self.wpas.wait_for_event("DPP-AUTH-SUCCESS")
self.wpas.wait_for_event("DPP-CONF-RECEIVED")
def test_pkex_iwd_as_configurator_retransmit(self):
self.rule_xchg_resp.enabled = True
self.rule_reveal_resp.enabled = True
self.start_iwd_pkex_configurator(self.device[0])
self.start_wpas_pkex('secret123', identifier="test", initiator=True,
role='enrollee')
self.wpas.wait_for_event("DPP-AUTH-SUCCESS")
self.wpas.wait_for_event("DPP-CONF-RECEIVED")
def test_pkex_iwd_as_configurator_bad_group(self):
self.start_iwd_pkex_configurator(self.device[0])
self.start_wpas_pkex('secret123', identifier="test", initiator=True,
role='enrollee', curve='P-384')
self.wpas.wait_for_event(f"DPP-RX src={self.device[0].address} freq=2437 type=8")
self.wpas.wait_for_event("DPP-FAIL")
def test_pkex_iwd_to_iwd(self):
self.start_iwd_pkex_configurator(self.device[0])
self.device[1].autoconnect = True
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
# Check additional settings were carried over
with open('/tmp/ns0/ssidCCMP.psk', 'r') as f:
settings = f.read()
self.assertIn("SendHostname=true", settings)
def test_pkex_configurator_with_agent(self):
self.start_iwd_pkex_configurator(self.device[0], agent=True)
self.device[1].autoconnect = True
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
self.agent = None
def test_existing_network(self):
self.hapd.reload()
self.hapd.wait_for_event('AP-ENABLED')
IWD.copy_to_storage("existingProfile.psk", "/tmp/ns0/", "ssidCCMP.psk")
# Scan first so a network object exists, and its a known network
self.device[1].scan()
self.wd.wait_for_object_condition(self.device[1], 'obj.scanning == True')
self.wd.wait_for_object_condition(self.device[1], 'obj.scanning == False')
self.start_iwd_pkex_configurator(self.device[0])
self.device[1].autoconnect = False
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
# Check additional settings were carried over
with open('/tmp/ns0/ssidCCMP.psk', 'r') as f:
settings = f.read()
self.assertIn("SendHostname=true", settings)
def test_existing_incorrect_profile(self):
self.hapd.reload()
self.hapd.wait_for_event('AP-ENABLED')
IWD.copy_to_storage("existingProfile.psk", "/tmp/ns0/", "ssidCCMP.psk")
# Start connecting
self.device[1].autoconnect = True
self.wd.wait_for_object_condition(self.device[1], 'obj.state == DeviceState.connecting')
# We should be able to start DPP despite the connecting state
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
self.start_iwd_pkex_configurator(self.device[0])
self.assertEqual(self.device[1].state, DeviceState.disconnected)
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
def test_existing_hidden_network(self):
self.hapd_hidden.reload()
self.hapd_hidden.wait_for_event('AP-ENABLED')
IWD.copy_to_storage("existingProfile.psk", "/tmp/ns0/", "ssidHidden.psk")
# Scan first so a network object exists, and its a known network
self.device[1].scan()
self.wd.wait_for_object_condition(self.device[1], 'obj.scanning == True')
self.wd.wait_for_object_condition(self.device[1], 'obj.scanning == False')
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
self.device[1].autoconnect = False
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
# Check additional settings were carried over
with open('/tmp/ns0/ssidHidden.psk', 'r') as f:
settings = f.read()
self.assertIn("Hidden=true", settings)
def test_hidden_network(self):
self.hapd_hidden.reload()
self.hapd_hidden.wait_for_event('AP-ENABLED')
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
self.device[1].autoconnect = False
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device[1], condition)
# Check additional settings were carried over
with open('/tmp/ns0/ssidHidden.psk', 'r') as f:
settings = f.read()
self.assertIn("Hidden=true", settings)
def setUp(self):
ns0 = ctx.get_namespace('ns0')
self.wpas = Wpas('wpas.conf')
self.wd = IWD(True)
self.wd_ns0 = IWD(True, iwd_storage_dir='/tmp/ns0', namespace=ns0)
self.device = []
self.device.append(self.wd.list_devices(1)[0])
self.device.append(self.wd_ns0.list_devices(1)[0])
self.hapd = HostapdCLI('hostapd.conf')
self.hapd.disable()
self.hapd_hidden = HostapdCLI('ssidHidden.conf')
self.hapd_hidden.disable()
self.hwsim = Hwsim()
self.rule_xchg_resp = self.hwsim.rules.create()
self.rule_xchg_resp.prefix = 'd0'
self.rule_xchg_resp.match_offset = 24
self.rule_xchg_resp.match = '04 09 50 6f 9a 1a 01 08'
self.rule_xchg_resp.match_times = 1
self.rule_xchg_resp.drop = True
self.rule_reveal_resp = self.hwsim.rules.create()
self.rule_reveal_resp.prefix = 'd0'
self.rule_reveal_resp.match_offset = 24
self.rule_reveal_resp.match = '04 09 50 6f 9a 1a 01 0a'
self.rule_reveal_resp.match_times = 1
self.rule_reveal_resp.drop = True
self.rule_reveal_req = self.hwsim.rules.create()
self.rule_reveal_req.prefix = 'd0'
self.rule_reveal_req.match_offset = 24
self.rule_reveal_req.match = '04 09 50 6f 9a 1a 01 09'
self.rule_reveal_req.match_times = 1
self.rule_reveal_req.drop = True
def tearDown(self):
# Tests end in various states, don't fail when tearing down.
try:
self.device[0].disconnect()
self.device[0].dpp_pkex_stop()
self.device[1].disconnect()
self.device[1].dpp_pkex_stop()
except:
pass
self.wpas.dpp_configurator_remove()
self.wpas.clean_up()
self.wd = None
self.wd_ns0 = None
self.device = None
self.wpas = None
self.hapd = None
self.rule_xchg_resp = None
IWD.clear_storage()
IWD.clear_storage('/tmp/ns0')
@classmethod
def setUpClass(cls):
pass
@classmethod
def tearDownClass(cls):
pass
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -1,2 +1,5 @@
[Security]
Passphrase=secret123
[IPv4]
SendHostname=true

View File

@ -0,0 +1,9 @@
hw_mode=g
channel=6
ssid=ssidHidden
wpa=1
wpa_pairwise=TKIP
wpa_passphrase=secret123
ignore_broadcast_ssid=1

View File

@ -0,0 +1,5 @@
[Security]
Passphrase=secret123
[Settings]
Hidden=true

View File

@ -0,0 +1,107 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
from iwd import IWD, SharedCodeAgent, DeviceState
from iwd import DeviceProvisioning
from wpas import Wpas
from hostapd import HostapdCLI
from hwsim import Hwsim
from config import ctx
from time import time
import os
class Test(unittest.TestCase):
def auto_connect(self):
IWD.copy_to_storage('ssidCCMP.psk')
self.device.autoconnect = True
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
def test_configurator_stops_on_disconnect(self):
self.auto_connect()
self.device.dpp_start_configurator()
self.device.disconnect()
condition = 'obj.state == DeviceState.disconnected'
self.wd.wait_for_object_condition(self.device, condition)
self.assertEqual(self.device._device_provisioning.started, False)
def test_enrollee_stops_on_connect(self):
# Scan to get a list of networks
self.device.scan()
self.wd.wait_for_object_condition(self.device, 'obj.scanning == True')
self.wd.wait_for_object_condition(self.device, 'obj.scanning == False')
self.device.dpp_start_enrollee()
network = self.device.get_ordered_network("ssidCCMP")
network.network_object.connect()
condition = 'obj.state == DeviceState.connected'
self.wd.wait_for_object_condition(self.device, condition)
self.assertEqual(self.device._device_provisioning.started, False)
def test_enrollee_disconnects_automatically(self):
self.auto_connect()
self.device.dpp_start_enrollee()
condition = 'obj.state == DeviceState.disconnected'
self.wd.wait_for_object_condition(self.device, condition)
def test_enrollee_autoconnect_stays_on(self):
# Put in an autoconnecting state, no saved profile though
self.device.autoconnect = True
self.device.dpp_start_enrollee()
# DPP should set autoconnect false, but then re-enable after it stops
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
self.wd.wait_for_object_condition(self.device._device_provisioning, "obj.started == True")
# Stop DPP
self.device.dpp_stop()
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == True")
def test_enrollee_autoconnect_stays_off(self):
# Autoconnect should be off by default
self.device.dpp_start_enrollee()
# DPP should set autoconnect false, but stay off after it stops
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
self.wd.wait_for_object_condition(self.device._device_provisioning, "obj.started == True")
# Stop DPP
self.device.dpp_stop()
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
def setUp(self):
self.wd = IWD(True)
self.device = self.wd.list_devices(1)[0]
def tearDown(self):
self.wd.stop()
self.wd = None
@classmethod
def setUpClass(cls):
hapd = HostapdCLI(config="hostapd.conf")
hapd.reload()
hapd.wait_for_event("AP-ENABLED")
@classmethod
def tearDownClass(cls):
pass
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -3,3 +3,4 @@ ctrl_interface=/tmp/rad1-p2p-wpas
update_config=0
pmf=2
dpp_config_processing=2
p2p_disabled=1

View File

@ -104,7 +104,7 @@ class Test(unittest.TestCase):
self.assertTrue(self.profile_is_encrypted('ssidCCMP.psk'))
# Tests that a profile that doesn't decrypt wont become a known network
# Tests that a profile that doesn't decrypt won't become a known network
def test_decryption_failure(self):
bad_config = \
'''

View File

@ -1,2 +1,5 @@
[Security]
Passphrase=secret123
[General]
AutoConnect=false

View File

@ -0,0 +1,76 @@
import unittest
import sys
import sys
import os
from scapy.layers.dot11 import *
from scapy.arch import str2mac
try:
from scapy.arch import get_if_raw_hwaddr
except:
from scapy.arch.unix import get_if_raw_hwaddr
from time import time, sleep
from threading import Thread
def if_hwaddr(iff):
return str2mac(get_if_raw_hwaddr(iff)[1])
def config_mon(iface, channel):
"""set the interface in monitor mode and then change channel using iw"""
os.system("ip link set dev %s down" % iface)
os.system("iw dev %s set type monitor" % iface)
os.system("ip link set dev %s up" % iface)
os.system("iw dev %s set channel %d" % (iface, channel))
class AP:
def __init__(self, ssid, psk, mac=None, mode="stdio", iface="wlan0", channel=1):
self.channel = channel
self.iface = iface
self.mode = mode
if self.mode == "iface":
if not mac:
mac = if_hwaddr(iface)
config_mon(iface, channel)
if not mac:
raise Exception("Need a mac")
else:
self.mac = mac
self.boottime = time()
def get_radiotap_header(self):
return RadioTap()
def dot11_beacon(self, contents):
evil_packet = (
self.get_radiotap_header()
/ Dot11(
subtype=8, addr1="ff:ff:ff:ff:ff:ff", addr2=self.mac, addr3=self.mac
)
/ Dot11Beacon(cap=0x3101)
/ contents
)
self.sendp(evil_packet)
def run(self, contents):
interval = 0.05
num_beacons = 100
while num_beacons:
self.dot11_beacon(contents)
sleep(interval)
num_beacons -= 1
def start(self, contents):
self.thread = Thread(target=self.run, args=(contents,))
self.thread.start()
def stop(self):
self.thread.join()
def sendp(self, packet, verbose=False):
if self.mode == "stdio":
x = packet.build()
sys.stdout.buffer.write(struct.pack("<L", len(x)) + x)
sys.stdout.buffer.flush()
return
assert self.mode == "iface"
sendp(packet, iface=self.iface, verbose=False)

View File

@ -0,0 +1,7 @@
[SETUP]
num_radios=2
start_iwd=0
hwsim_medium=yes
[rad1]
reserve=true

View File

@ -0,0 +1,37 @@
#! /usr/bin/python3
import unittest
import sys
import sys
import os
from fake_ap import AP
sys.path.append('../util')
from iwd import IWD
# Probe frame that causes IWD to crash
beacon=b'\xdd\nPo\x9a\t\x0e\x00\x00\x19\x10\x00\xdd/Po\x9a\t\x0c\x02\x00\x00\xdd\x05\x03\x03\x03Po\x9a\x10\x00\x0b\x05\x0e\x00\x00\x00\x00\x0b\x05\x00\x00\x00\xdd\x05\x00\x03\x03\x03\x03\x00\x00\x00\xdd\x05\x03\x03\x03\x03\x03'
class Test(unittest.TestCase):
def test_beacon_crash(self):
wd = IWD(True)
devs = wd.list_devices()
self.assertEqual(len(devs), 1)
devs[0].autoconnect = True
os.system("iw phy rad1 interface add wlan1 type managed")
ap = AP("evilAP", "password1234", mode="iface", iface="wlan1", channel=4)
ap.start(beacon)
condition = "obj.scanning == True"
wd.wait_for_object_condition(devs[0], condition)
condition = "obj.scanning == False"
wd.wait_for_object_condition(devs[0], condition)
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -12,7 +12,7 @@ from hostapd import HostapdCLI
class TestWpaNetwork(unittest.TestCase):
'''
The bellow test cases excesise the following connection scenarios:
The below test cases excesise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -12,7 +12,7 @@ from hostapd import HostapdCLI
class TestOpenNetwork(unittest.TestCase):
'''
The bellow test cases excesise the following connection scenarios:
The below test cases excesise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -12,7 +12,7 @@ from hostapd import HostapdCLI
class TestWpaNetwork(unittest.TestCase):
'''
The bellow test cases excesise the following connection scenarios:
The below test cases excesise the following connection scenarios:
Network config is
present at start time: Connect: AutoConnect: Result:

View File

@ -4,17 +4,15 @@ import unittest
import sys
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
import testutil
from hwsim import Hwsim
import os
from configparser import ConfigParser
class Test(unittest.TestCase):
def connect_network(self, wd, device, network):
ordered_network = device.get_ordered_network(network)
ordered_network = device.get_ordered_network(network, full_scan=True)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
@ -30,7 +28,7 @@ class Test(unittest.TestCase):
wd.wait_for_object_condition(ordered_network.network_object, condition)
def test_connection_success(self):
wd = IWD(True, '/tmp')
wd = self.wd
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
@ -38,6 +36,11 @@ class Test(unittest.TestCase):
devices = wd.list_devices(1)
device = devices[0]
# Set the signals so that the 2.4GHz ranking will be higher
self.ssidccmp_2g_rule.signal = -2000
self.ssidccmp_5g_rule.signal = -8000
#
# Connect to the PSK network, then Hotspot so IWD creates 2 entries in
# the known frequency file.
@ -75,8 +78,10 @@ class Test(unittest.TestCase):
#
self.assertIsNotNone(psk_freqs)
self.assertIsNotNone(psk_uuid)
self.assertIn('5180', psk_freqs)
self.assertIn('2412', psk_freqs)
# The 2.4GHz frequency should come first, as it was ranked higher
self.assertEqual('2412', psk_freqs[0])
self.assertEqual('5180', psk_freqs[1])
self.assertIsNotNone(hs20_freqs)
self.assertIsNotNone(hs20_uuid)
@ -92,6 +97,10 @@ class Test(unittest.TestCase):
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
# Now set the signals so that the 5GHz ranking will be higher
self.ssidccmp_2g_rule.signal = -8000
self.ssidccmp_5g_rule.signal = -2000
#
# Reconnect, this should generate a completely new UUID since we
# previously forgot the network.
@ -120,8 +129,78 @@ class Test(unittest.TestCase):
self.assertIsNotNone(psk_freqs)
self.assertIsNotNone(psk_uuid2)
self.assertNotEqual(psk_uuid, psk_uuid2)
self.assertIn('5180', psk_freqs)
self.assertIn('2412', psk_freqs)
# Now the 5GHz frequency should be first
self.assertEqual('5180', psk_freqs[0])
self.assertEqual('2412', psk_freqs[1])
def test_maximum_frequencies(self):
psk_agent = PSKAgent("secret123")
self.wd.register_psk_agent(psk_agent)
devices = self.wd.list_devices(1)
device = devices[0]
# Connect and generate a known frequencies file
self.connect_network(self.wd, device, 'ssidCCMP')
self.wd.unregister_psk_agent(psk_agent)
#
# Rewrite the known frequencies file to move the valid network
# frequencies to the end, past the maximum for a quick scan
#
config = ConfigParser()
config.read('/tmp/iwd/.known_network.freq')
for s in config.sections():
if os.path.basename(config[s]['name']) == 'ssidCCMP.psk':
config.set(s, 'list', "2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484 2412 5180")
break
self.wd.stop()
with open('/tmp/iwd/.known_network.freq', 'w') as f:
config.write(f)
self.wd = IWD(True)
devices = self.wd.list_devices(1)
device = devices[0]
device.autoconnect = True
device.wait_for_event("autoconnect_quick")
condition = "obj.scanning == True"
self.wd.wait_for_object_condition(device, condition)
condition = "obj.scanning == False"
self.wd.wait_for_object_condition(device, condition)
#
# Check that the quick scan didn't return any results
#
with self.assertRaises(Exception):
device.get_ordered_network("ssidCCMP", scan_if_needed=False)
device.wait_for_event("autoconnect_full")
condition = "obj.scanning == True"
self.wd.wait_for_object_condition(device, condition)
condition = "obj.scanning == False"
self.wd.wait_for_object_condition(device, condition)
#
# The full scan should now see the network
#
device.get_ordered_network("ssidCCMP", scan_if_needed=False)
def setUp(self):
self.wd = IWD(True)
def tearDown(self):
self.wd.stop()
self.wd = None
@classmethod
def setUpClass(cls):
@ -129,10 +208,23 @@ class Test(unittest.TestCase):
conf = '[General]\nDisableANQP=0\n'
os.system('echo "%s" > /tmp/main.conf' % conf)
hwsim = Hwsim()
cls.ssidccmp_2g_rule = hwsim.rules.create()
cls.ssidccmp_2g_rule.source = hwsim.get_radio('rad1').addresses[0]
cls.ssidccmp_2g_rule.enabled = True
cls.ssidccmp_5g_rule = hwsim.rules.create()
cls.ssidccmp_5g_rule.source = hwsim.get_radio('rad2').addresses[0]
cls.ssidccmp_5g_rule.enabled = True
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
os.remove('/tmp/main.conf')
cls.ssidccmp_2g_rule.remove()
cls.ssidccmp_5g_rule.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -2,6 +2,7 @@
num_radios=5
start_iwd=0
reg_domain=US
hwsim_medium=yes
[HOSTAPD]
rad0=ssidNew.conf

View File

@ -11,7 +11,7 @@ from iwd import NetworkType
class TestMFP(unittest.TestCase):
'''
The bellow test cases excesise the following MFP option setting scenarios:
The below test cases excesise the following MFP option setting scenarios:
IWD_MFP: AP_MFP: Result:
0 0 No MFP, connection succeeds

View File

@ -0,0 +1,2 @@
[IPv4]
SendHostname=true

View File

@ -137,7 +137,7 @@ class Test(unittest.TestCase):
# since (T2 - T1) / 2 is shorter than 60s. It is now about 10s since the last
# renewal or 5s before the next DHCPREQUEST frame that is going to be lost. We'll
# wait T1 seconds, so until about 10s after the failed attempt, we'll check that
# there was no renewal by that time, just in case, and we'll reenable frame delivery.
# there was no renewal by that time, just in case, and we'll re-enable frame delivery.
# We'll then wait another 60s and we should see the lease has been successfully
# renewed some 10 seconds earlier on the 1st DHCPREQUEST retransmission.
#

View File

@ -81,14 +81,21 @@ class Test(unittest.TestCase):
self.assertEqual(expected_routes6, set(testutil.get_routes6(ifname)))
rclog = open('/tmp/resolvconf.log', 'r')
entries = rclog.readlines()
entries = [l.strip() for l in rclog.readlines()[-7:]]
rclog.close()
expected_rclog = ['-a %s.dns\n' % (ifname,), 'nameserver 192.168.1.2\n',
'nameserver 3ffe:501:ffff:100::10\n', 'nameserver 3ffe:501:ffff:100::50\n',
'-a %s.domain\n' % (ifname,), 'search test1\n', 'search test2\n']
# Every resolvconf -a run overwrites the previous settings. Check the last seven lines
# of our log since we care about the end result here.
self.assertEqual(expected_rclog, entries[-7:])
expected_rclog = [
'-a %s.dns' % (ifname,),
'nameserver 192.168.1.2',
'nameserver 3ffe:501:ffff:100::10',
'nameserver 3ffe:501:ffff:100::50',
'-a %s.domain' % (ifname,),
'search test1',
'search test2'
]
for line in expected_rclog:
self.assertIn(line, entries)
expected_rclog.remove(line)
device.disconnect()
condition = 'not obj.connected'

View File

@ -91,16 +91,11 @@ class Test(unittest.TestCase):
# using the same static config. The new client's ACD client should
# detect an IP conflict and not allow the device to reach the
# "connected" state although the DBus .Connect call will succeed.
ordered_network.network_object.connect()
self.assertEqual(dev2.state, iwd.DeviceState.connecting)
try:
# We should either stay in "connecting" indefinitely or move to
# "disconnecting"
condition = 'obj.state != DeviceState.connecting'
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
self.assertEqual(dev2.state, iwd.DeviceState.disconnecting)
except TimeoutError:
dev2.disconnect()
with self.assertRaises(iwd.FailedEx):
ordered_network.network_object.connect(timeout=500)
condition = 'obj.state == DeviceState.disconnected'
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1)
del dev2

View File

@ -0,0 +1,78 @@
import unittest
import sys
import os
sys.path.append('../util')
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
class Test(unittest.TestCase):
def connect_failure(self, ex):
self.failure_triggered = True
def test_netconfig_timeout(self):
IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk')
wd = IWD(True)
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
devices = wd.list_devices(1)
device = devices[0]
ordered_network = device.get_ordered_network('ap-ns1')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.failure_triggered = False
# Set our error handler here so we can check if it fails
ordered_network.network_object.connect(
wait=False,
timeout=1000,
error_handler=self.connect_failure
)
# IWD should attempt to try both BSS's with both failing netconfig.
# Then the autoconnect list should be exhausted, and IWD should
# transition to a disconnected state, then proceed to full autoconnect.
device.wait_for_event("netconfig-failed", timeout=1000)
device.wait_for_event("netconfig-failed", timeout=1000)
device.wait_for_event("disconnected")
device.wait_for_event("autoconnect_full")
# The connect call should have failed
self.assertTrue(self.failure_triggered)
condition = "obj.scanning"
wd.wait_for_object_condition(device, condition)
condition = "not obj.scanning"
wd.wait_for_object_condition(device, condition)
# IWD should attempt to connect, but it will of course fail again.
device.wait_for_event("netconfig-failed", timeout=1000)
device.disconnect()
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
@classmethod
def setUpClass(cls):
cls.orig_path = os.environ['PATH']
os.environ['PATH'] = '/tmp/test-bin:' + os.environ['PATH']
IWD.copy_to_storage('resolvconf', '/tmp/test-bin')
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
os.system('rm -rf /tmp/radvd.conf /tmp/resolvconf.log /tmp/test-bin')
os.environ['PATH'] = cls.orig_path
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,2 @@
[Security]
Passphrase=EasilyGuessedPassword

View File

@ -0,0 +1,41 @@
hw_mode=g
channel=1
ssid=TestFT
utf8_ssid=1
ctrl_interface=/var/run/hostapd
r1_key_holder=120000000001
nas_identifier=dummy1
wpa=2
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
# time but we want to force FT
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=1
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
# Allow PMK cache to be shared opportunistically among configured interfaces
# and BSSes (i.e., all configurations within a single hostapd process).
okc=1
mobility_domain=1234
reassociation_deadline=60000
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
# Push mode only needed for 8021x, not PSK mode since msk already known
pmk_r1_push=0
# Allow locally generated FT response so we don't have to configure push/pull
# between BSSes running as separate hostapd processes as in the test-runner
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -0,0 +1,41 @@
hw_mode=g
channel=2
ssid=TestFT
utf8_ssid=1
ctrl_interface=/var/run/hostapd
r1_key_holder=120000000002
nas_identifier=dummy2
wpa=2
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
# time but we want to force FT
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=1
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
# Allow PMK cache to be shared opportunistically among configured interfaces
# and BSSes (i.e., all configurations within a single hostapd process).
okc=1
mobility_domain=1234
reassociation_deadline=60000
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
# Push mode only needed for 8021x, not PSK mode since msk already known
pmk_r1_push=0
# Allow locally generated FT response so we don't have to configure push/pull
# between BSSes running as separate hostapd processes as in the test-runner
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -0,0 +1,8 @@
[SETUP]
num_radios=3
start_iwd=0
hwsim_medium=yes
[HOSTAPD]
rad0=ft-psk-ccmp-1.conf
rad1=ft-psk-ccmp-2.conf

View File

@ -0,0 +1,3 @@
[General]
EnableNetworkConfiguration=true
RoamRetryInterval=1

View File

@ -0,0 +1,91 @@
#! /usr/bin/python3
import unittest
import sys, os
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from iwd import DeviceState
from hwsim import Hwsim
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def test_roam_before_netconfig(self):
wd = IWD(True)
device = wd.list_devices(1)[0]
device.get_ordered_network('TestFT', full_scan=True)
device.connect_bssid(self.bss_hostapd[1].bssid, wait=False)
self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
device.wait_for_event("connecting (netconfig)")
roam_to = 0
roam_from = 1
# Roam back and forth, ensuring that the state transitions between
# roaming and connecting (netconfig).
for _ in range(0, 5):
self.rules[roam_to].signal = -2000
self.rules[roam_from].signal = -8000
# Station should internally transition to roaming, but remain in a
# connecting state on DBus
device.wait_for_event("ft-roaming")
self.assertEqual(device.state, DeviceState.connecting)
self.bss_hostapd[roam_to].wait_for_event(f'AP-STA-CONNECTED {device.address}')
device.wait_for_event("connecting (netconfig)")
tmp = roam_from
roam_from = roam_to
roam_to = tmp
self.bss_hostapd[roam_from].deauthenticate(device.address)
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
rule0 = hwsim.rules.create()
rule0.source = cls.bss_hostapd[0].bssid
rule0.signal = -6000
rule0.enabled = True
rule1 = hwsim.rules.create()
rule1.source = cls.bss_hostapd[1].bssid
rule1.signal = -2000
rule1.enabled = True
cls.rules = [rule0, rule1]
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None
cls.rules = None
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -47,11 +47,6 @@ class Test(unittest.TestCase):
# Normal success case
def test_owe_transition(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_owe2.disable()
self.hapd_open2.disable()
@ -59,15 +54,8 @@ class Test(unittest.TestCase):
# Normal success case
def test_owe_transition_multi_network(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_open2.set_value('vendor_elements', 'dd17506f9a1c02000000f1000c6f77652d68696464656e2d32')
self.hapd_open2.set_value('ssid', 'transition-2')
self.hapd_open2.reload()
self.hapd_owe2.set_value('vendor_elements', 'dd17506f9a1c02000000f0000c7472616e736974696f6e2d32')
self.hapd_owe2.set_value('ssid', 'owe-hidden-2')
self.hapd_owe2.reload()
@ -75,11 +63,6 @@ class Test(unittest.TestCase):
# Two pairs of open/OWE BSS's (OWE BSS's have different SSIDs) */
def test_owe_transition_multi_bss(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_open2.set_value('vendor_elements', 'dd17506f9a1c02000000f3000c6f77652d68696464656e2d32')
self.hapd_open2.set_value('ssid', 'transition')
self.hapd_open2.reload()
@ -91,11 +74,6 @@ class Test(unittest.TestCase):
# Two pairs of open/OWE BSS's (OWE BSS's have same SSID) */
def test_owe_transition_multi_bss_same_ssid(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_open2.set_value('vendor_elements', 'dd15506f9a1c02000000f3000a6f77652d68696464656e')
self.hapd_open2.set_value('ssid', 'transition')
self.hapd_open2.reload()
@ -107,11 +85,6 @@ class Test(unittest.TestCase):
# Normal success autoconnect case
def test_owe_transition_autoconnect(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_owe2.disable()
self.hapd_open2.disable()
@ -124,8 +97,6 @@ class Test(unittest.TestCase):
def test_owe_transition_invalid_open_bssid(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000ff000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_owe2.disable()
self.hapd_open2.disable()
@ -135,8 +106,6 @@ class Test(unittest.TestCase):
# OWE BSS has invalid BSSID in OWE transition element
# Expected connection to Open BSS
def test_owe_transition_invalid_owe_bssid(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000ff000a7472616e736974696f6e')
self.hapd_owe.reload()
@ -148,8 +117,6 @@ class Test(unittest.TestCase):
# No OWE hidden network exists
# Expected connection to Open BSS
def test_owe_transition_no_hidden_found(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.disable()
self.hapd_owe2.disable()
@ -160,11 +127,6 @@ class Test(unittest.TestCase):
# Directly connect to valid OWE hidden network
# Expected connection failure
def test_owe_transition_connect_hidden_valid(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_owe2.disable()
self.hapd_open2.disable()
@ -189,7 +151,6 @@ class Test(unittest.TestCase):
def test_owe_transition_band_info(self):
self.hapd_open.set_value('vendor_elements', 'dd17506f9a1c02000000f1000a6f77652d68696464656e5103')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.set_value('channel', '3')
self.hapd_owe.reload()
@ -201,7 +162,6 @@ class Test(unittest.TestCase):
def test_owe_transition_wrong_band_info(self):
self.hapd_open.set_value('vendor_elements', 'dd17506f9a1c02000000f1000a6f77652d68696464656e5102')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.set_value('channel', '3')
self.hapd_owe.reload()
@ -212,11 +172,6 @@ class Test(unittest.TestCase):
# OWE Transition pair + additional open network with the same SSID
def test_owe_transition_extra_open(self):
self.hapd_open.set_value('vendor_elements', 'dd15506f9a1c02000000f1000a6f77652d68696464656e')
self.hapd_open.reload()
self.hapd_owe.set_value('vendor_elements', 'dd15506f9a1c02000000f0000a7472616e736974696f6e')
self.hapd_owe.reload()
self.hapd_open2.set_value('ssid', 'transition')
self.hapd_open2.reload()
@ -235,17 +190,19 @@ class Test(unittest.TestCase):
def setUp(self):
self.wd = IWD(True)
self.hapd_owe = HostapdCLI(config='ssidOWE.conf')
self.hapd_owe.default()
self.hapd_open = HostapdCLI(config='ssidOpen.conf')
self.hapd_open.default()
self.hapd_owe2 = HostapdCLI(config='ssidOWE-2.conf')
self.hapd_owe2.default()
self.hapd_open2 = HostapdCLI(config='ssidOpen-2.conf')
self.hapd_open2.default()
self.hwsim = Hwsim()
def tearDown(self):
IWD.clear_storage()
self.hapd_owe.set_value('channel', '1')
self.wd = None
self.hapd_open = None
self.hapd_owe = None

View File

@ -7,3 +7,5 @@ ieee80211w=1
wpa=2
wpa_key_mgmt=OWE
rsn_pairwise=CCMP
vendor_elements=dd17506f9a1c02000000f0000c7472616e736974696f6e2d32

View File

@ -7,6 +7,7 @@ ieee80211w=1
wpa=2
wpa_key_mgmt=OWE
rsn_pairwise=CCMP
vendor_elements=dd15506f9a1c02000000f0000a7472616e736974696f6e
# You would conventionally use these options but hostapd does not include an
# IE for the OWE network, hence vendor_elements must be used directly

View File

@ -1,3 +1,4 @@
channel=1
ssid=transition-2
bssid=02:00:00:00:f2:00
vendor_elements=dd17506f9a1c02000000f1000c6f77652d68696464656e2d32

View File

@ -1,6 +1,7 @@
channel=1
ssid=transition
bssid=02:00:00:00:f0:00
vendor_elements=dd15506f9a1c02000000f1000a6f77652d68696464656e
# You would conventionally use these options but hostapd does not include an
# IE for the OWE network, hence vendor_elements must be used directly

View File

@ -64,6 +64,39 @@ class Test(unittest.TestCase):
self.assertRaises(Exception, testutil.test_ifaces_connected,
(hapd0.ifname, device.name, True, True))
def test_auto_default_group(self):
wd = IWD()
hapd = HostapdCLI(config='ssidOWE-1.conf')
devices = wd.list_devices(1)
device = devices[0]
device.get_ordered_network('ssidOWE')
device.connect_bssid(hapd.bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
# Should have rejected group 20, but still connected on 19
self.assertEqual(device.event_ocurred("ecc-group-rejected"), True)
testutil.test_iface_operstate()
testutil.test_ifaces_connected(device.name, hapd.ifname)
device.disconnect()
device.connect_bssid(hapd.bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
# IWD should have used the default group, no rejection
self.assertEqual(device.event_ocurred("ecc-group-rejected"), False)
testutil.test_iface_operstate()
testutil.test_ifaces_connected(device.name, hapd.ifname)
@classmethod
def setUpClass(cls):
pass

View File

@ -0,0 +1,114 @@
#!/usr/bin/python3
import unittest
import sys
sys.path.append('../util')
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def validate_connection(self, wd, ssid, hostapd, expected_group):
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
devices = wd.list_devices(1)
self.assertIsNotNone(devices)
device = devices[0]
device.disconnect()
network = device.get_ordered_network(ssid, full_scan=True)
self.assertEqual(network.type, NetworkType.psk)
network.network_object.connect()
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
wd.wait(2)
testutil.test_iface_operstate(intf=device.name)
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
# Initial connection PMKSA should not be used. So we should see the
# SAE group set.
sta_status = hostapd.sta_status(device.address)
self.assertEqual(int(sta_status["sae_group"]), expected_group)
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(network.network_object, condition)
wd.unregister_psk_agent(psk_agent)
network.network_object.connect(wait=False)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
wd.wait(2)
testutil.test_iface_operstate(intf=device.name)
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
# Having connected once prior we should have a PMKSA and SAE should not
# have been used.
sta_status = hostapd.sta_status(device.address)
self.assertNotIn("sae_group", sta_status.keys())
device.disconnect()
condition = 'not obj.connected'
wd.wait_for_object_condition(network.network_object, condition)
hostapd.pmksa_flush()
wd.wait(5)
network.network_object.connect()
device.wait_for_event("pmksa-invalid-pmkid")
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
wd.wait(2)
testutil.test_iface_operstate(intf=device.name)
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
# Manually flushing the PMKSA from the AP then reconnecting we should
# have failed (INVALID_PMKID) then retried the same BSS with SAE, not
# PMKSA.
sta_status = hostapd.sta_status(device.address)
self.assertEqual(int(sta_status["sae_group"]), expected_group)
def test_pmksa_sae(self):
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
def setUp(self):
self.hostapd.default()
self.wd = IWD(True)
def tearDown(self):
self.wd.clear_storage()
self.wd = None
@classmethod
def setUpClass(cls):
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
@classmethod
def tearDownClass(cls):
pass
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,7 @@
[SETUP]
num_radios=2
start_iwd=0
hwsim_medium=yes
[HOSTAPD]
rad0=ssidSAE.conf

View File

@ -0,0 +1,12 @@
hw_mode=g
channel=1
ssid=ssidSAE
wpa=2
wpa_key_mgmt=SAE
wpa_pairwise=CCMP
sae_password=secret123
sae_groups=19
ieee80211w=2
sae_pwe=0
rsn_preauth=1

View File

@ -0,0 +1,114 @@
#! /usr/bin/python3
import unittest
import sys, os
sys.path.append('../util')
from iwd import IWD
from iwd import NetworkType
from hostapd import HostapdCLI
from packaging import version
from subprocess import run
import re
import testutil
#
# The CSA handling was added in kernel 6.8, so for any earlier kernel this test
# won't pass.
#
def kernel_is_newer(min_version="6.8"):
proc = run(["uname", "-r"], capture_output=True)
version_str = proc.stdout.decode("utf-8")
match = re.match(r"(\d+\.\d+)", version_str)
if not match:
return False
return version.parse(match.group(1)) >= version.parse(min_version)
class Test(unittest.TestCase):
def test_channel_switch_during_roam(self):
wd = self.wd
device = wd.list_devices(1)[0]
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.assertFalse(self.bss_hostapd[0].list_sta())
self.assertFalse(self.bss_hostapd[1].list_sta())
device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
testutil.test_iface_operstate(device.name)
testutil.test_ifaces_connected(self.bss_hostapd[0].ifname, device.name)
self.assertRaises(Exception, testutil.test_ifaces_connected,
(self.bss_hostapd[1].ifname, device.name, True, True))
# Start a channel switch and wait for it to begin
self.bss_hostapd[1].chan_switch(6, wait=False)
self.bss_hostapd[1].wait_for_event("CTRL-EVENT-STARTED-CHANNEL-SWITCH")
# Initiate a roam immediately which should get rejected by the kernel
device.roam(self.bss_hostapd[1].bssid)
# IWD should authenticate, then proceed to association
device.wait_for_event("ft-authenticating")
device.wait_for_event("ft-roaming")
# The kernel should reject the association, which should trigger a
# disconnect
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
for hapd in self.bss_hostapd:
hapd.default()
self.wd.stop()
self.wd = None
def setUp(self):
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
if not kernel_is_newer():
raise unittest.SkipTest()
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf'),
HostapdCLI(config='ft-psk-ccmp-3.conf') ]
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
unused.disable()
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
cls.bss_hostapd[2].set_address('12:00:00:00:00:03')
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None

View File

@ -91,70 +91,32 @@ class Test(unittest.TestCase):
wd.wait_for_object_condition(device, condition)
def test_ft_psk(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[0].set_value('ft_over_ds', '0')
self.bss_hostapd[0].set_value('ocv', '1')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[1].set_value('ft_over_ds', '0')
self.bss_hostapd[0].set_value('ocv', '1')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.validate_connection(wd)
self.validate_connection(self.wd)
def test_ft_psk_over_ds(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[0].set_value('ft_over_ds', '1')
self.bss_hostapd[0].set_value('ocv', '1')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[1].set_value('ft_over_ds', '1')
self.bss_hostapd[1].set_value('ocv', '1')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.validate_connection(wd, over_ds=True)
self.validate_connection(self.wd, over_ds=True)
def test_reassociate_psk(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'WPA-PSK')
self.bss_hostapd[0].set_value('ft_over_ds', '0')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'WPA-PSK')
self.bss_hostapd[1].set_value('ft_over_ds', '0')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.validate_connection(wd)
self.validate_connection(self.wd)
def test_roam_packet_loss(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[0].set_value('ft_over_ds', '0')
self.bss_hostapd[0].set_value('ocv', '1')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[1].set_value('ft_over_ds', '0')
self.bss_hostapd[0].set_value('ocv', '1')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.validate_connection(wd, pkt_loss=True)
self.validate_connection(self.wd, pkt_loss=True)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
@ -166,6 +128,15 @@ class Test(unittest.TestCase):
self.rule1.enabled = False
self.rule2.enabled = False
for hapd in self.bss_hostapd:
hapd.default()
self.wd.stop()
self.wd = None
def setUp(self):
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
@ -173,9 +144,10 @@ class Test(unittest.TestCase):
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf'),
HostapdCLI(config='ft-psk-ccmp-3.conf') ]
cls.bss_hostapd[2].disable()
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
unused.disable()
rad0 = hwsim.get_radio('rad0')
rad3 = hwsim.get_radio('rad3')
@ -205,8 +177,9 @@ class Test(unittest.TestCase):
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None
cls.rule0.enabled = False
cls.rule0.remove()
cls.rule1.remove()
cls.rule2.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -0,0 +1,112 @@
#! /usr/bin/python3
import unittest
import sys, os
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hwsim import Hwsim
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def validate_connection(self, wd):
device = wd.list_devices(1)[0]
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
self.assertFalse(self.bss_hostapd[0].list_sta())
self.assertFalse(self.bss_hostapd[1].list_sta())
device.connect_bssid(self.bss_hostapd[0].bssid)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
testutil.test_iface_operstate(device.name)
testutil.test_ifaces_connected(self.bss_hostapd[0].ifname, device.name)
self.assertRaises(Exception, testutil.test_ifaces_connected,
(self.bss_hostapd[1].ifname, device.name, True, True))
self.rule0.enabled = True
device.roam(self.bss_hostapd[1].bssid)
device.clear_events()
device.wait_for_event("handshake-started")
self.bss_hostapd[1].deauthenticate(device.address, reason=15, test=1)
# Check that iwd is on BSS 1 once out of roaming state and doesn't
# go through 'disconnected', 'autoconnect', 'connecting' in between
from_condition = 'obj.state == DeviceState.roaming'
to_condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_change(device, from_condition, to_condition)
def test_disconnect_during_handshake(self):
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'WPA-PSK')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'WPA-PSK')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
for hapd in self.bss_hostapd:
hapd.default()
self.wd.stop()
self.wd = None
def setUp(self):
self.wd = IWD(True)
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
IWD.copy_to_storage('TestFT.psk')
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
unused.disable()
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
rad1 = hwsim.get_radio('rad1')
cls.rule0 = hwsim.rules.create()
cls.rule0.destination = rad1.addresses[0]
cls.rule0.prefix = '08'
cls.rule0.drop = True
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.bss_hostapd = None
cls.rule0.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -41,24 +41,14 @@ class Test(unittest.TestCase):
self.assertRaises(Exception, testutil.test_ifaces_connected,
(prev.ifname, device.name, True, True))
# FT-over-Air failure, should stay connected
def test_ft_over_air_failure(self):
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[0].set_value('ft_over_ds', '0')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.rule2.enabled = True
self.rule3.enabled = True
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[1].set_value('ft_over_ds', '0')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
device = self.wd.list_devices(1)[0]
wd = IWD(True)
device = wd.list_devices(1)[0]
self.connect(wd, device, self.bss_hostapd[0])
self.connect(self.wd, device, self.bss_hostapd[0])
self.rule0.enabled = True
@ -70,11 +60,112 @@ class Test(unittest.TestCase):
self.rule0.enabled = False
# IWD should then try BSS 2, and succeed
self.verify_roam(wd, device, self.bss_hostapd[0], self.bss_hostapd[2])
device.wait_for_event('ft-roaming', timeout=60)
self.verify_roam(self.wd, device, self.bss_hostapd[0], self.bss_hostapd[2])
self.bss_hostapd[2].deauthenticate(device.address)
# Tests that an associate even should cause a disconnect
def test_ft_over_air_assoc_timeout(self):
self.rule2.enabled = True
self.rule3.enabled = True
self.assoc_rule.enabled = True
device = self.wd.list_devices(1)[0]
self.connect(self.wd, device, self.bss_hostapd[0])
device.wait_for_event('ft-roaming', timeout=60)
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
self.wd.wait_for_object_condition(device, condition)
# FT-over-Air failure with Invalid PMKID, should reassociate
def test_ft_over_air_fallback(self):
self.rule_bss0.signal = -8000
self.rule_bss0.enabled = True
self.rule_bss1.signal = -7500
self.rule_bss1.enabled = True
self.rule_bss2.signal = -6000
self.rule_bss2.enabled = True
# This will cause this BSS to reject any FT roams as its unable to
# get keys from other APs
self.bss_hostapd[2].set_value('ft_psk_generate_local', '0')
self.bss_hostapd[2].reload()
device = self.wd.list_devices(1)[0]
self.connect(self.wd, device, self.bss_hostapd[0])
# IWD should connect, then attempt a roam to BSS 1, which should
# fail and cause a fallback to reassociation
device.wait_for_event('ft-fallback-to-reassoc', timeout=60)
device.wait_for_event('roaming', timeout=60)
self.verify_roam(self.wd, device, self.bss_hostapd[0], self.bss_hostapd[2])
# Trigger another roam
self.rule_bss2.signal = -8000
device.wait_for_event('ft-roaming', timeout=60)
# Ensure an FT roam back to a properly configured AP works.
self.verify_roam(self.wd, device, self.bss_hostapd[2], self.bss_hostapd[1])
self.bss_hostapd[1].deauthenticate(device.address)
condition = 'obj.state == DeviceState.disconnected'
self.wd.wait_for_object_condition(device, condition)
# FT-over-Air failure with Invalid PMKID. The ranking is such that other
# FT candidates are available so it should FT elsewhere rather than
# retry with reassociation
def test_ft_over_air_fallback_retry_ft(self):
self.rule_bss0.signal = -8000
self.rule_bss0.enabled = True
self.rule_bss1.signal = -7300
self.rule_bss1.enabled = True
self.rule_bss2.signal = -7100
self.rule_bss2.enabled = True
# This will cause this BSS to reject any FT roams as its unable to
# get keys from other APs
self.bss_hostapd[2].set_value('ft_psk_generate_local', '0')
self.bss_hostapd[2].reload()
device = self.wd.list_devices(1)[0]
self.connect(self.wd, device, self.bss_hostapd[0])
# IWD should connect, then attempt a roam to BSS 1, which should
# fail and cause the rank to be re-computed. This should then put
# bss 1 as the next candidate (since the FT factor is removed)
device.wait_for_event('ft-fallback-to-reassoc', timeout=60)
device.wait_for_event('ft-roaming', timeout=60)
self.verify_roam(self.wd, device, self.bss_hostapd[0], self.bss_hostapd[1])
self.bss_hostapd[1].deauthenticate(device.address)
condition = 'obj.state == DeviceState.disconnected'
self.wd.wait_for_object_condition(device, condition)
def test_ft_deauth_before_association(self):
self.rule2.enabled = True
self.rule3.enabled = True
device = self.wd.list_devices(1)[0]
self.connect(self.wd, device, self.bss_hostapd[0])
device.wait_for_event('ft-authenticating', timeout=60)
self.bss_hostapd[1].deauthenticate(device.address)
condition = 'obj.state == DeviceState.disconnected'
self.wd.wait_for_object_condition(device, condition)
def setUp(self):
self.wd = IWD(True)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
@ -85,6 +176,17 @@ class Test(unittest.TestCase):
self.rule0.enabled = False
self.rule1.enabled = False
self.rule2.enabled = False
self.rule3.enabled = False
self.rule_bss0.enabled = False
self.rule_bss1.enabled = False
self.rule_bss2.enabled = False
self.assoc_rule.enabled = False
for hapd in self.bss_hostapd:
hapd.default()
self.wd.stop()
self.wd = None
@classmethod
def setUpClass(cls):
@ -106,6 +208,11 @@ class Test(unittest.TestCase):
cls.rule0.prefix = 'b0'
cls.rule0.drop = True
# Drop Associate frames
cls.assoc_rule = hwsim.rules.create()
cls.assoc_rule.prefix = '20'
cls.assoc_rule.drop = True
# Drop Action frames
cls.rule1 = hwsim.rules.create()
cls.rule1.bidirectional = True
@ -116,13 +223,20 @@ class Test(unittest.TestCase):
cls.rule2 = hwsim.rules.create()
cls.rule2.source = hwsim.get_radio('rad0').addresses[0]
cls.rule2.signal = -8000
cls.rule2.enabled = True
# Causes IWD to first prefer BSS 1 to roam, then BSS 2.
cls.rule3 = hwsim.rules.create()
cls.rule3.source = hwsim.get_radio('rad2').addresses[0]
cls.rule3.signal = -7000
cls.rule3.enabled = True
cls.rule_bss0 = hwsim.rules.create()
cls.rule_bss0.source = hwsim.get_radio('rad0').addresses[0]
cls.rule_bss1 = hwsim.rules.create()
cls.rule_bss1.source = hwsim.get_radio('rad1').addresses[0]
cls.rule_bss2 = hwsim.rules.create()
cls.rule_bss2.source = hwsim.get_radio('rad2').addresses[0]
HostapdCLI.group_neighbors(*cls.bss_hostapd)
@classmethod
def tearDownClass(cls):
@ -130,6 +244,12 @@ class Test(unittest.TestCase):
cls.bss_hostapd = None
cls.rule0.remove()
cls.rule1.remove()
cls.rule2.remove()
cls.rule3.remove()
cls.assoc_rule.remove()
cls.rule_bss0.remove()
cls.rule_bss1.remove()
cls.rule_bss2.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -13,7 +13,7 @@ wpa=2
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=1
ieee80211w=0
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
@ -33,7 +33,9 @@ pmk_r1_push=0
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -13,7 +13,7 @@ wpa=2
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=1
ieee80211w=0
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
@ -33,7 +33,9 @@ pmk_r1_push=0
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -13,7 +13,7 @@ wpa=2
wpa_key_mgmt=FT-PSK
wpa_pairwise=CCMP
wpa_passphrase=EasilyGuessedPassword
ieee80211w=1
ieee80211w=0
rsn_preauth=1
rsn_preauth_interfaces=lo
disable_pmksa_caching=0
@ -33,7 +33,9 @@ pmk_r1_push=0
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
# CONFIG_BRIDGE enabled in the kernel.
ft_psk_generate_local=1
rkh_pull_timeout=50
ft_over_ds=0
ap_table_expiration_time=36000
ap_table_max_size=10
rrm_neighbor_report=1
ocv=1

View File

@ -3,3 +3,6 @@ DisableMacAddressRandomization=true
[General]
RoamRetryInterval=1
# For disconnect_during_handshake_test
ManagementFrameProtection=0

View File

@ -14,8 +14,7 @@ class Test(unittest.TestCase):
# Tests a crash reported where multiple roam scans combined with an AP
# disconnect result in a crash getting scan results.
#
def validate(self):
wd = IWD(True)
def validate(self, wd):
device = wd.list_devices(1)[0]
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
@ -43,14 +42,15 @@ class Test(unittest.TestCase):
wd.wait_for_object_condition(device, condition)
def test_ap_disconnect_no_neighbors(self):
self.validate()
self.validate(self.wd)
def test_ap_disconnect_neighbors(self):
HostapdCLI.group_neighbors(*self.bss_hostapd)
self.validate()
self.validate(self.wd)
def setUp(self):
self.wd = IWD(True)
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
@ -63,6 +63,9 @@ class Test(unittest.TestCase):
self.bss_hostapd[0].remove_neighbor(self.bss_hostapd[1].bssid)
self.bss_hostapd[1].remove_neighbor(self.bss_hostapd[0].bssid)
self.wd.stop()
self.wd = None
@classmethod
def setUpClass(cls):
hwsim = Hwsim()
@ -78,12 +81,21 @@ class Test(unittest.TestCase):
cls.bss_hostapd[0].set_value('ocv', '0')
cls.bss_hostapd[0].set_value('ieee80211w', '0')
rad0 = hwsim.get_radio('rad0')
rad1 = hwsim.get_radio('rad1')
cls.rule0 = hwsim.rules.create()
cls.rule0.source = 'any'
cls.rule0.source = rad0.addresses[0]
cls.rule0.bidirectional = True
cls.rule0.signal = -8000
cls.rule0.enabled = True
cls.rule1 = hwsim.rules.create()
cls.rule1.source = rad1.addresses[0]
cls.rule1.bidirectional = True
cls.rule1.signal = -8500
cls.rule1.enabled = True
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
@ -92,6 +104,7 @@ class Test(unittest.TestCase):
IWD.clear_storage()
cls.bss_hostapd = None
cls.rule0.remove()
cls.rule1.remove()
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -17,7 +17,7 @@ from hwsim import Hwsim
class Test(unittest.TestCase):
# Normally the time between a failed roam attempt and the next roam attempt
# is 60 seconds (default RoamRetryInterval). Test that we retry roaming
# faster if the transision looks like this: LOW [roam] [same bss] HIGH LOW.
# faster if the transition looks like this: LOW [roam] [same bss] HIGH LOW.
def test_fast_retry(self):
hwsim = Hwsim()

View File

@ -15,7 +15,7 @@ from hostapd import HostapdCLI
from hwsim import Hwsim
class Test(unittest.TestCase):
# Test that we do not periodically retry roaming if the transision looks
# Test that we do not periodically retry roaming if the transition looks
# like this: LOW [roam] [new bss] HIGH.
def test_stop_retry(self):
hwsim = Hwsim()

View File

@ -55,14 +55,13 @@ class Test(unittest.TestCase):
wd.clear_storage()
def test_SAE(self):
self.hostapd.set_value('sae_pwe', '0');
self.hostapd.set_value('sae_groups', '19');
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
wd = IWD(True)
self.validate_connection(wd)
wd.clear_storage()
def setUp(self):
self.hostapd.default()
@classmethod
def setUpClass(cls):
cls.hostapd = HostapdCLI(config='ssidSAE-Clogging.conf')

View File

@ -8,3 +8,5 @@ wpa_pairwise=CCMP
sae_password=secret123|mac=ff:ff:ff:ff:ff:ff
sae_anti_clogging_threshold=2
ieee80211w=2
sae_pwe=0
sae_groups=19

View File

@ -13,7 +13,7 @@ import testutil
from config import ctx
class Test(unittest.TestCase):
def validate_connection(self, wd, ft=True):
def validate_connection(self, wd, ft=True, check_used_pmksa=False):
device = wd.list_devices(1)[0]
# This won't guarantee all BSS's are found, but at least ensures that
@ -37,6 +37,14 @@ class Test(unittest.TestCase):
self.assertRaises(Exception, testutil.test_ifaces_connected,
(self.bss_hostapd[1].ifname, device.name, True, True))
# If PMKSA was used, hostapd should not include the sae_group key in
# its status for the station.
sta_status = self.bss_hostapd[0].sta_status(device.address)
if check_used_pmksa:
self.assertNotIn("sae_group", sta_status.keys())
else:
self.assertIn("sae_group", sta_status.keys())
device.roam(self.bss_hostapd[1].bssid)
# Check that iwd is on BSS 1 once out of roaming state and doesn't
@ -88,6 +96,31 @@ class Test(unittest.TestCase):
self.validate_connection(wd, True)
def test_ft_roam_pmksa(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-SAE SAE')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-SAE SAE')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'FT-PSK')
self.bss_hostapd[2].reload()
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
self.validate_connection(wd, True)
device = wd.list_devices(1)[0]
device.disconnect()
for hapd in self.bss_hostapd:
hapd.deauthenticate(device.address)
wd.wait(5)
self.validate_connection(wd, True, check_used_pmksa=True)
def test_reassociate_roam_success(self):
wd = IWD(True)
@ -103,6 +136,31 @@ class Test(unittest.TestCase):
self.validate_connection(wd, False)
def test_reassociate_roam_pmksa(self):
wd = IWD(True)
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'SAE')
self.bss_hostapd[0].reload()
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'SAE')
self.bss_hostapd[1].reload()
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'WPA-PSK')
self.bss_hostapd[2].reload()
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
self.validate_connection(wd, False)
device = wd.list_devices(1)[0]
device.disconnect()
for hapd in self.bss_hostapd:
hapd.deauthenticate(device.address)
wd.wait(5)
self.validate_connection(wd, False, check_used_pmksa=True)
def tearDown(self):
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')

View File

@ -12,8 +12,7 @@ from hostapd import HostapdCLI
class Test(unittest.TestCase):
def validate_connection(self, wd):
def validate_connection(self, wd, ssid):
devices = wd.list_devices(1)
self.assertIsNotNone(devices)
device = devices[0]
@ -25,7 +24,7 @@ class Test(unittest.TestCase):
condition = 'obj.connected_network is not None'
wd.wait_for_object_condition(device, condition)
ordered_network = device.get_ordered_network('ssidSAE')
ordered_network = device.get_ordered_network(ssid)
self.assertTrue(ordered_network.network_object.connected)
@ -35,31 +34,38 @@ class Test(unittest.TestCase):
wd.wait_for_object_condition(ordered_network.network_object, condition)
def test_SAE(self):
self.hostapd.set_value('sae_pwe', '0')
self.hostapd.set_value('sae_groups', '19')
self.hostapd.reload()
IWD.copy_to_storage("profiles/ssidSAE.psk.default", name="ssidSAE.psk")
self.hostapd.wait_for_event("AP-ENABLED")
wd = IWD(True)
self.validate_connection(wd)
self.validate_connection(wd, "ssidSAE")
def test_SAE_H2E(self):
self.hostapd.set_value('sae_pwe', '1')
self.hostapd.set_value('sae_groups', '20')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
IWD.copy_to_storage("profiles/ssidSAE.psk.default", name="ssidSAE-H2E.psk")
self.hostapd_h2e.set_value('sae_groups', '20')
self.hostapd_h2e.reload()
self.hostapd_h2e.wait_for_event("AP-ENABLED")
wd = IWD(True)
self.validate_connection(wd)
self.validate_connection(wd, "ssidSAE-H2E")
def test_SAE_H2E_password_identifier(self):
IWD.copy_to_storage("profiles/ssidSAE.psk.identifier", name="ssidSAE-H2E.psk")
self.hostapd_h2e.set_value('sae_groups', '20')
self.hostapd_h2e.reload()
self.hostapd_h2e.wait_for_event("AP-ENABLED")
wd = IWD(True)
self.validate_connection(wd, "ssidSAE-H2E")
def setUp(self):
self.hostapd.default()
def tearDown(self):
IWD.clear_storage()
@classmethod
def setUpClass(cls):
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
IWD.copy_to_storage('ssidSAE.psk')
pass
@classmethod
def tearDownClass(cls):
IWD.clear_storage()
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -13,7 +13,7 @@ import testutil
class Test(unittest.TestCase):
def validate_connection(self, wd):
def validate_connection(self, wd, ssid, hostapd, expected_group):
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
@ -23,11 +23,11 @@ class Test(unittest.TestCase):
device.disconnect()
network = device.get_ordered_network('ssidSAE', full_scan=True)
network = device.get_ordered_network(ssid, full_scan=True)
self.assertEqual(network.type, NetworkType.psk)
network.network_object.connect()
network.network_object.connect(wait=False)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
@ -35,7 +35,11 @@ class Test(unittest.TestCase):
wd.wait(2)
testutil.test_iface_operstate(intf=device.name)
testutil.test_ifaces_connected(if0=device.name, if1=self.hostapd.ifname)
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
sta_status = hostapd.sta_status(device.address)
self.assertEqual(int(sta_status["sae_group"]), expected_group)
device.disconnect()
@ -45,48 +49,29 @@ class Test(unittest.TestCase):
wd.unregister_psk_agent(psk_agent)
def test_SAE(self):
self.hostapd.set_value('sae_pwe', '0')
self.hostapd.set_value('sae_groups', '19')
self.hostapd.set_value('vendor_elements', '')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
def test_SAE_force_group_19(self):
self.hostapd.set_value('sae_pwe', '0')
self.hostapd.set_value('sae_groups', '19')
# Vendor data from APs which require group 19 be used first
# TODO: (for all tests) verify the expected group was used
self.hostapd.set_value('vendor_elements', 'dd0cf4f5e8050500000000000000')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
def test_SAE_Group20(self):
self.hostapd.set_value('sae_pwe', '0')
self.hostapd.set_value('sae_groups', '20')
self.hostapd.set_value('vendor_elements', '')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 20)
def test_SAE_H2E(self):
self.hostapd.set_value('sae_pwe', '1')
self.hostapd.set_value('sae_groups', '19')
self.hostapd.set_value('vendor_elements', '')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
self.hostapd_h2e.set_value('sae_groups', '19')
self.hostapd_h2e.reload()
self.hostapd_h2e.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd, "ssidSAE-H2E", self.hostapd_h2e, 19)
def test_SAE_H2E_Group20(self):
self.hostapd.set_value('sae_pwe', '1')
self.hostapd.set_value('sae_groups', '20')
self.hostapd.set_value('vendor_elements', '')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd)
self.hostapd_h2e.set_value('sae_groups', '20')
self.hostapd_h2e.reload()
self.hostapd_h2e.wait_for_event("AP-ENABLED")
self.validate_connection(self.wd, "ssidSAE-H2E", self.hostapd_h2e, 20)
def setUp(self):
self.hostapd.default()
self.wd = IWD(True)
def tearDown(self):
@ -96,6 +81,7 @@ class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
@classmethod
def tearDownClass(cls):

View File

@ -0,0 +1,104 @@
#!/usr/bin/python3
import unittest
import sys
import os
sys.path.append('../util')
import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def validate_connection(self, wd, hostapd, rejected=False):
devices = wd.list_devices(1)
self.assertIsNotNone(devices)
device = devices[0]
device.autoconnect = True
if rejected:
device.wait_for_event("ecc-group-rejected", timeout=60)
condition = 'obj.state == DeviceState.connected'
wd.wait_for_object_condition(device, condition)
wd.wait(2)
testutil.test_iface_operstate(intf=device.name)
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
if not rejected:
self.assertEqual(device.event_ocurred("ecc-group-rejected"), False)
print(hostapd._get_status())
sta_status = hostapd.sta_status(device.address)
print(sta_status)
self.assertEqual(int(sta_status["sae_group"]), 19)
device.disconnect()
# IWD should:
# - Connect, fail with group 20
# - Retry, succeed with group 19
# - Disconnect
# - Connect, try only group 19
def test_auto_selection(self):
IWD.copy_to_storage("profiles/ssidSAE.psk.default", name="ssidSAE.psk")
self.validate_connection(self.wd, self.hostapd, rejected=True)
self.validate_connection(self.wd, self.hostapd, rejected=False)
# Try group 19 first
def test_default_group_enabled(self):
IWD.copy_to_storage("profiles/ssidSAE.psk.default_group", name="ssidSAE.psk")
self.validate_connection(self.wd, self.hostapd)
# Try group 19 first, with H2E
def test_default_group_enabled_h2e(self):
IWD.copy_to_storage("profiles/ssidSAE-H2E.psk.default_group", name="ssidSAE-H2E.psk")
self.validate_connection(self.wd, self.hostapd_h2e)
# Same as auto-selection but won't retain the default group setting
def test_default_group_disabled(self):
IWD.copy_to_storage("profiles/ssidSAE.psk.most_secure", name="ssidSAE.psk")
self.validate_connection(self.wd, self.hostapd, rejected=True)
# IWD should then retry but use only group 19
self.validate_connection(self.wd, self.hostapd, rejected=True)
def setUp(self):
self.hostapd.default()
self.hostapd.set_value('sae_groups', '19')
self.hostapd.set_value('sae_pwe', '0')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.wd = IWD(True)
self.wd.clear_storage()
os.system("ls /tmp/iwd")
def tearDown(self):
self.wd.clear_storage()
self.wd = None
@classmethod
def setUpClass(cls):
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
cls.hostapd.default()
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
cls.hostapd_h2e.default()
@classmethod
def tearDownClass(cls):
pass
if __name__ == '__main__':
unittest.main(exit=True)

View File

@ -37,13 +37,16 @@ class Test(unittest.TestCase):
self.validate_connection(wd, 'InvalidSecret')
def test_no_supported_groups(self):
hostapd = HostapdCLI(config='ssidSAE.conf')
hostapd.set_value('sae_groups', '1')
hostapd.reload()
self.hostapd.set_value('sae_groups', '21')
self.hostapd.reload()
wd = IWD(True)
self.validate_connection(wd, 'secret123')
def setUp(self):
self.hostapd = HostapdCLI(config='ssidSAE.conf')
self.hostapd.default()
@classmethod
def setUpClass(cls):
pass

View File

@ -1,7 +1,8 @@
[SETUP]
num_radios=2
num_radios=3
start_iwd=0
hwsim_medium=yes
[HOSTAPD]
rad0=ssidSAE.conf
rad1=ssidSAE-H2E.conf

View File

@ -4,3 +4,6 @@
# hardware, but fails when used in simulated environment with mac80211_hwsim.
# Disable MAC randomization for the tests with hidden networks.
DisableMacAddressRandomization=true
[General]
DisablePMKSA=true

View File

@ -0,0 +1,2 @@
[Security]
Passphrase=secret123

View File

@ -0,0 +1,5 @@
[Security]
Passphrase=secret123
[Settings]
UseDefaultEccGroup=true

View File

@ -0,0 +1,2 @@
[Security]
Passphrase=secret123

View File

@ -0,0 +1,5 @@
[Security]
Passphrase=secret123
[Settings]
UseDefaultEccGroup=true

View File

@ -0,0 +1,3 @@
[Security]
Passphrase=withidentifier
PasswordIdentifier=myidentifier

View File

@ -0,0 +1,5 @@
[Security]
Passphrase=secret123
[Settings]
UseDefaultEccGroup=false

View File

@ -0,0 +1,12 @@
hw_mode=g
channel=1
ssid=ssidSAE-H2E
wpa=2
wpa_key_mgmt=SAE
wpa_pairwise=CCMP
sae_password=secret123
sae_password=withidentifier|id=myidentifier
sae_groups=19
ieee80211w=2
sae_pwe=1

View File

@ -5,6 +5,7 @@ ssid=ssidSAE
wpa=2
wpa_key_mgmt=SAE
wpa_pairwise=CCMP
sae_password=secret123|mac=ff:ff:ff:ff:ff:ff
sae_password=secret123
sae_groups=19
ieee80211w=2
sae_pwe=0

View File

@ -40,10 +40,8 @@ class Test(unittest.TestCase):
# needed because the hwsim rule only matches once and must be matched
# on the first commit, not during group negotiation.
#
hostapd = HostapdCLI(config='ssidSAE.conf')
hostapd.set_value('vendor_elements', 'dd0cf4f5e8050500000000000000')
hostapd.set_value('sae_groups', '19')
hostapd.reload()
self.hostapd.set_value('vendor_elements', 'dd0cf4f5e8050500000000000000')
self.hostapd.reload()
hwsim = Hwsim()
bss_radio = hwsim.get_radio('rad0')
@ -64,10 +62,8 @@ class Test(unittest.TestCase):
rule0.remove()
def test_sta_confirm_not_acked(self):
hostapd = HostapdCLI(config='ssidSAE.conf')
hostapd.set_value('vendor_elements', 'dd0cf4f5e8050500000000000000')
hostapd.set_value('sae_groups', '19')
hostapd.reload()
self.hostapd.set_value('vendor_elements', 'dd0cf4f5e8050500000000000000')
self.hostapd.reload()
hwsim = Hwsim()
bss_radio = hwsim.get_radio('rad0')
@ -87,6 +83,10 @@ class Test(unittest.TestCase):
rule0.remove()
def setUp(self):
self.hostapd = HostapdCLI(config='ssidSAE.conf')
self.hostapd.default()
@classmethod
def setUpClass(cls):
pass

View File

@ -43,9 +43,6 @@ class Test(unittest.TestCase):
wd.unregister_psk_agent(psk_agent)
def test_ccmp(self):
self.hostapd.set_value('rsn_pairwise', 'CCMP')
self.hostapd.reload()
self.hostapd.wait_for_event("AP-ENABLED")
self.validate_connection_success(self.wd)
def test_gcmp(self):
@ -67,6 +64,7 @@ class Test(unittest.TestCase):
self.validate_connection_success(self.wd)
def setUp(self):
self.hostapd.default()
self.wd = IWD(True)
def tearDown(self):

View File

@ -8,11 +8,12 @@ import iwd
from iwd import IWD
from iwd import PSKAgent
from iwd import NetworkType
from hostapd import HostapdCLI
import testutil
class Test(unittest.TestCase):
def test_connection_success(self):
def test_incorrect_password(self):
wd = IWD(True)
psk_agent = PSKAgent("InvalidPassword")
@ -34,6 +35,35 @@ class Test(unittest.TestCase):
wd.unregister_psk_agent(psk_agent)
def test_deauth_after_connection(self):
wd = IWD(True)
hostapd = HostapdCLI(config="ssidWPA2.conf")
psk_agent = PSKAgent("secret123")
wd.register_psk_agent(psk_agent)
devices = wd.list_devices(1)
self.assertIsNotNone(devices)
device = devices[0]
ordered_network = device.get_ordered_network('ssidWPA2')
self.assertEqual(ordered_network.type, NetworkType.psk)
condition = 'not obj.connected'
wd.wait_for_object_condition(ordered_network.network_object, condition)
ordered_network.network_object.connect(wait=False)
device.wait_for_event("authenticating")
# Trigger a deauth just after authenticating
hostapd.deauthenticate(device.address)
device.wait_for_event("disconnected")
wd.unregister_psk_agent(psk_agent)
@classmethod
def setUpClass(cls):
pass

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