For PSK networks we have netdev.c taking care of setting the linkmode &
operstate. For open adhoc networks, netdev.c was never involved which
resulted in linkmode & operstate never being set. Fix this by invoking
the necessary magic when a connection is established.
adhoc_reset() destroys ssid and sta_states but leaves the pointers
around, athough the adhoc_state structure is not always freed.
This causes a segfault when exiting iwd after a client has done
adhoc start and adhoc stop on a device since adhoc_reset() is called
from adhoc_sta_free although it was previously called from
adhoc_leave_cb().
The netdev_leave_adhoc() returns a negative errno on errors and zero
on success, but adhoc_dbus_stop() assumed the inverse when checking for
an error.
Also, the DBus message was not being referenced in adhoc->pending and
then adhoc_leave_cb() segfaulted attempting to dereference it.
It seems some APs send the IGTK key in big endian format (it is a
uin16). The kernel rightly reports an -EINVAL error when iwd issues a
NEW_KEY with such a value, resulting in the connection being aborted.
Work around this by trying to detect big-endian key indexes and 'fixing'
them up.
This bug has been in here since OWE was written, but a similar bug also
existed in hostapd which allowed the PTK derivation to be identical.
In January 2020 hostapd fixed this bug, which now makes IWD incompatible
when using group 20 or 21.
This patch fixes the bug for IWD, so now OWE should be compatible with
recent hostapd version. This will break compatibility with old hostapd
versions which still have this bug.
If the AP only supports an AKM which requires an auth protocol
CMD_AUTHENTICATE/CMD_ASSOCIATE must be supported or else the
auth protocol cannot be run. All the auth protocols are started
assuming that the card supports these commands, but the support
was never checked when parsing supported commands.
This patch will prevent any fullMAC cards from using
SAE/FILS/OWE. This was the same behavior as before, just an
earlier failure path.
This function was intended to catch socket errors and destroy the group
but it would leak the l_io object if that happened, and if called on
ordinary shutdown it could cause a crash. Since we're now assuming
that the netlink socket operations never fail just remove it.
Only add constants for parsing the Device Information subelement as that
is the main thing we care about in P2P code. And since our own WFD IEs
will likely only need to contain the Device Information subelement, we
don't need builder utilities. We do need iterator utilities because we
may receive WFD IEs with more subelements.
In some cases a P2P peer will ACK our frame but not reply on the first
attempt, and other implementations seem to handle this by going back to
retransmitting the frame at a high rate until it gets ACKed again, at
which point they will again give the peer a longer time to tx the
response frame. Implement the same logic here by adding a
retries_on_ack parameter that takes the number of additional times we
want to restart the normal retransmit counter after we received no
response frame on the first attempt. So passing 0 maintains the
current behaviour, 1 for 1 extra attempt, etc.
In effect we may retransmit a frame about 15 * (retry_on_ack + 1) *
<in-kernel retransmit limit> times. The kernel/driver retransmits a
frame a number of times if there's no ACK (I've seen about 20 normally)
at a high frequency, if that fails we retry the whole process 15 times
inside frame-xchg.c and if we still get no ACK at any point, we give up.
If we do get an ACK, we wait for a response frame and if we don't get
that we will optionally reset the retry counter and restart the whole
thing retry_on_ack times.
In order to support AlwaysRandomizeAddress and AddressOverride, station will
set the desired address into the handshake object. Then, netdev checks if
this was done and will use that address rather than generate one.
This patch adds two new options to a network provisioning file:
AlwaysRandomizeAddress={true,false}
If true, IWD will randomize the MAC address on each connection to this
network. The address does not persists between connections, any new
connection will result in a different MAC.
AddressOverride=<MAC>
If set, the MAC address will be set to <MAC> assuming its a valid MAC
address.
These two options should not be used together, and will only take effect
if [General].AddressRandomization is set to 'network' in the IWD
config file.
If neither of these options are set, and [General].AddressRandomization
is set to 'network', the default behavior remains the same; the MAC
will be generated deterministically on a per-network basis.
Since frame_watch_remove_by_handler only forgets a given function +
user data pointers, and doesn't remove the frame prefixes added in the
kernel, we can avoid later re-registering those prefixes with the
kernel by keeping them in our local watchlist, and only replacing the
handler pointer with a dummy function.
If during WATCHLIST_NOTIFY{,_MATCHES,_NO_ARGS} one of the watch
notify callback triggers a call to watchlist_destroy, give up calling
remaining watches and destroy the watchlist without crashing. This is
useful in frame-xchg.c (P2P use case) where a frame watch may trigger
a move to a new state after receiving a specific frame, and remove one
group of frame watches (including its watchlist) to create a different
group.
For privacy reasons its advantageous to randomize or mask
the MAC address when connecting to networks, especially public
networks.
This patch allows netdev to generate a new MAC address on a
per-network basis. The generated MAC will remain the same when
connecting to the same network. This allows reauthentications
or roaming to work, and not have to fully re-connect (which would
be required if the MAC changed on every connection).
Changing the MAC requires bringing the interface down. This does
lead to potential race conditions with respect to external
processes. There are two potential conditions which are explained
in a TODO comment in this patch.
This API is being added to support per-network MAC address
generation. The MAC is generated based on the network SSID
and the adapters permanent address using HMAC-SHA256. The
SHA digest is then constrained to make it MAC address
compliant.
Generating the MAC address like this will ensure that the
MAC remains the same each time a given SSID is connected to.
Make sure a frame callback is free to call frame_xchg_stop without
causing a crash. Frame callback here means the one that gets
called if our tx frame was ACKed and triggered a respone frame that
matched one of the provided prefixes, within the given time.
All in all a frame callback is allowed to call either
frame_xchg_stop or frame_xchg_startv or neither. Same applies to
the final callback (called when no matching responses received).
Don't crash if the user calls frame_xchg_stop(wdev) from inside the
frame exchange's final callback. That call is going to be redundant but
it's convenient to do this inside a cleanup function for a given wdev
without having to check whether any frame exchange was actually running.
This API was updated to take an extra boolean which will
automatically power up the device while changing the MAC
address. Since this is what IWD does anyways we can avoid
the need for an intermediate callback and go right into
netdev_initial_up_cb.
iwd would fail to connect using EAP-TLS when no CA certificate was
provided as it checked for successful loading of the CA certificate
instead of the client certificate when attempting to load the client
certificate.
The password for EAP-GTC is directly used in an EAP response. The
response buffer is created on the stack so an overly large password
could cause a stack overflow.
mac80211 drivers seem to send the disconnect event which is triggered by
CMD_DISCONNECT prior to the CMD_DISCONNECT response. However, some
drivers, namely brcmfmac, send the response first and then send the
disconnect event. This confused iwd when a connection was immediately
triggered after a disconnection (network switch operation).
Fix this by making sure that connected variable isn't set until the
connect event is actually processed, and ignore disconnect events which
come after CMD_DISCONNECT has alredy succeeded.
For nl80211 sockets other than our main l_genl object use socket io
directly, to avoid creating many instances of l_genl. The only reason
we use multiple sockets is to work around an nl80211 design quirk that
requires closing the socket to unregister management frame watches.
Normally there should not be a need to create multiple sockets in a
program.
Add a little state machine and a related API, to simplify sending out a
frame, receiving the Ack / No-ack status and (if acked) waiting for a
response frame from the target device, one of a list of possible
frame prefixes. The nl80211 API for this makes it complicated
enough that this new API seems to be justified, on top of that there's a
quirk when using the brcmfmac driver where the nl80211 response
(containing the operation's cookie), the Tx Status event and the response
Frame event are received from nl80211 in reverse order (not seen with
other drivers so far), further complicating what should be a pretty
simple task.
Try to better deduplicate the frame watches. Until now we'd check if
we'd already registered a given frame body prefix with the kernel, or a
matching more general prefix (shorter). Now also try to check if we
have already have a watch with the same callback pointer and user_data
value, and:
* an identical or shorter (more general) prefix, in that case ignore
the new watch completely.
* a longer (more specific) prefix, in that case forget the existing
watch.
The use case for this is when we have a single callback for multiple
watches and multiple frame types, and inside that callback we're looking
at the frame body again and matching it to frame types. In that case
we don't want that function to be called multiple times for one frame
event.
In frame_watch_group_remove I forgot to actually match the group to be
removed by both wdev_id and group_id. group_ids are unique only in the
scope of one wdev.
I forgot to actually add new groups being created in
frame_watch_group_get to the watch_groups queue, meaning that we'd
re-create the group every time a new watch was added to the group.
Processing the duplicated TLVs while connecting to a malicious AP may lead
to overflow of the response buffer. This patch ensures that the
duplicated TLVs are not parsed.
The pending wiphy state 'use_default' variable was not set early enough
in some circumstances resulting in weird behavior for blacklisted
drivers. Fix this by adding a manager_wiphy_dump_done callback which
will properly initialize the use_default value.
Fixes: c4b2f10483 ("manager: Handle missing NEW_WIPHY events")
brcmfmac does not allow the removal of the default / primary interface.
So there isn't much point in having iwd attempt this.
Another issue is that brcmfmac _does_ allow the deletion of non-default
interfaces. So starting iwd on a system with a station & ap interface
active can result in iwd attempting to delete all the interfaces. Given
the above, it succeeds in deleting the ap interface but not the station
one. In strange circumstances it might end up thinking that the ap
interface is the 'default' and trying to use it, whereas it was just
successfully removed.
==192== Conditional jump or move depends on uninitialised value(s)
==192== at 0x4531D3: l_queue_find (queue.c:346)
==192== by 0x42F1F8: manager_config_notify (manager.c:667)
==192== by 0x45A895: process_multicast (genl.c:970)
==192== by 0x45A895: received_data (genl.c:1037)
==192== by 0x4577B2: io_callback (io.c:126)
==192== by 0x456B0D: l_main_iterate (main.c:473)
==192== by 0x456BCB: l_main_run (main.c:520)
==192== by 0x456DDA: l_main_run_with_signal (main.c:642)
==192== by 0x4034B0: main (main.c:497)
The kernel emits NEW_WIPHY events whenever a new wiphy is registered.
Unfortunately these events are emitted under the 'legacy' semantics and
have a hard size limit of 4096 bytes. Unfortunately, it is possible for
a NEW_WIPHY message to exceed this limit (ath10k cards seem to be
affected in particular), which results in the kernel never sending these
messages out. This can lead to NEW_INTERFACE events being emitted with
a wiphy_id that had no corresponding NEW_WIPHY event emitted. Such a
sequence can confuse iwd's hardware detection logic, particularly during
hot-plug or system boot.
Fix this by re-dumping the wiphy if such a condition is detected. This
has some interaction with blacklisted wiphys, so the wiphy objects are
now always tracked and marked as blacklisted. Before, the blacklisted
wiphys were simply not added to the iwd list of tracked wiphys.
For the inner EAP methods that support generation of the key material
include it into imck generation. This allows to cryptographically
bind the inner method with the tunnel.
Windows Server 2008 - Network Policy Server (NPS) generates an invalid
Compound MAC for Cryptobinding TLV when is used within PEAPv0 due to
incorrect parsing of the message containing TLS Client Hello.
Setting L bit and including TLS Message Length field, even for the
packets that do not require fragmentation, corrects the issue. The
redundant TLS Message Length field in unfragmented packets doesn't
seem to affect the other server implementations.
Sometimes, at least with brcmfmac, the default interface apparently
takes a moment to get created after the NEW_WIPHY event. We didn't
really consider this case in the NEW_WIPHY handler and we've got a race
condition. It fixes the following bug for me:
https://bugs.archlinux.org/task/63912 -- tested by removing and
re-modprobing the brcmfmac module rather than rebooting.
To work around this wait for the NEW_INTERFACE event and then retry the
setup. We still do the initial attempt directly after NEW_WIPHY to
handle cases like wiphys with no default interfaces and pre-existing
wiphys.
We track mtime as the 'LastConnectedTime' of the network, and also sort
the known network list according to the last connected time.
Unfortunately we were never reacting to ATTRIB changes, and so were
never updating the network_info->connected_time whenever a network was
connected to.
Rework the logic to address this. This also fixes a small bug where the
connected_time was not set properly prior to removal / re-insertion of
the network_info.
We use the mtime on the network profile as the 'Last Connected Time'.
When we update any property and sync the file to disk, the mtime was not
preserved (since we were creating a new temporary file instead of
modifying the old one). This led to LastConnectedTime property change
being emitted / updated incorrectly when a writable property on the
KnownNetwork interface was updated.
Our design preference is to not call any callbacks in the _free/_destroy
method of a class (with the exception of explicit destroy callbacks
provided, if any).
Invoking the callback in this case was unnecessary: wsc_dbus_free was
already replying to pending connect / cancel messages. The only other
thing the callback would attempt to do is to set station back into
autoconnect mode. This was unnecessary as well since the netdev is
already down.
This change removes the callback invocation. Since wsc_enrollee_destroy
is now just calling wsc_enrollee_free, remove this from the API and
expose wsc_enrollee_free instead.
Split the WSC D-Bus interface class (struct wsc) into a base class
common to station mode and P2P mode (struct wsc_dbus) and station-
specific logic like scanning, saving the credentials as a known network
and triggering the station-mode connection (struct wsc_station_dbus).
Make the base class and its utilities public in wsc.h for P2P use.
Create struct wsc_enrollee which is allocated with wsc_enrollee_new,
taking a done callback as a parameter. The callback is always
called so there's no need for a separate destroy callback. The object
only lives until the done callback happens so wsc_enrollee_cancel/destroy
can only be used before this.
Looks like the rest of the file is simplified thanks to this.
This new API is independent of netdev.c and allows actually
unregistering from receiving notifications of frames, although with some
quirks. The current API only allowed the callback for a registration to
be forgotten but our process and/or the kernel would still be woken up
when matching frames were received because the kernel had no frame
unregister call. In the new API you can supply a group-id paramter when
registering frames. If it is non-zero the frame_watch_group_remove() call
can be used to remove all frame registrations that had a given group-id
by closing the netlink socket on which the notifications would be
received. This means though that it's a slightly costly operation.
The file is named frame-xchg.c because I'm thinking of also adding
utilities for sending frames and waiting for one of a number of replies
and handling the acked/un-acked information.
Instead of taking the credentials from wsc object directly, have the
caller pass these in. This makes it more consistent with how the
done_cb was done.
Split the interface-specific logic from the core WSC logic. The core
WSC code is the part that we can re-use between P2P and station and
doesn't include the D-Bus code, scanning for the target BSS or the
attempt to make a station mode connection.
Allow netdev_create_from_genl callers to draw a random or non-random MAC
and pass it in the parameter instead of a bool to tell us to generating
the MAC locally. In P2P we are generating the MAC some time before
creating the netdev in order to pass it to the peer during negotiation.
Some server implementation don't seem to provide the valid compound MACs.
In the meantime, iwd will ignore the invalid Crypto-Binding TLVs as their
usage is optional.
The intent was to check for the presence of the add_domain_name
operation, not add_dns operation.
Fixes: 930528e35e ("resolve: Add systemd-resolved domain name installer")
It seems that the kernel uses -EOPNOTSUPP if the change_station
operation is not implemented by the driver. However, some drivers do
implement change_station and choose to report -ENOTSUPP instead of
-EOPNOTSUPP.
To add to the confusion, EOPNOTSUPP and -ENOTSUPP are the same on some
systems (e.g. Gentoo). Be paranoid and allow both errors to be ignored
when sending CMD_SET_STATION.
Fixes: 0238ffb8d9 ("netdev: Use -EOPNOTSUPP instead of -ENOTSUPP")
The first if case should be -10950, not 10950. Without the negative
this first case would get hit every time since signal strength values
are always negative.
The Crypto Binding TLV is used to ensure that the EAP peer and the
EAP server participated in both the inner and the outer EAP
authentications of a PEAP authentication by cryptographically associating
the phase 1 and phase 2 authentications.
The usage of Crypto-Binding in PEAPv0 is optional and is triggered by
the reception of the Crypto-Binding TLV from the server.
The handler for EAP Extensions has been modified to support multiple
TLV types instead of the single Result TLV. This will allow to handle
the other TLVs such as Crypto-Binding TLV.
There are some server implementations that send requests that are
not "Password" but still want us send password. This commit modify
the behavior to send a warning and still try to auth with password.
This makes me able to auth with server in my school which sends
"Enter Aruba Login".
wpa_supplicant does not check if it is "Password".
The kernel uses -EOPNOTSUPP in the case of change_station operation not
being provided. On most systems -EOPNOTSUPP is defined to be the same
as -ENOTSUPP, but seemingly not all systems.
Previously, the key was installed once the tunnel was created
despite the outcome of the second authentication phase. Now, the
key installation is delayed until the successful completion of
the second authentication phase. This excludes the unnecessary
operations in the case of a failure and key reinstallation with
cypro-binding in use.
Commit 1057d8aa74 changed the device interface creation logic
from being unconditional inside netdev.c to instead use NETDEV_WATCH_*
events. However, this broke the assumption that the device interface
was created before all others. The effect is that the scan_wdev_add
might no longer be called prior to station interface being created. Fix
this by moving scan_wdev_add/remove calls to netdev.c instead.
Fixes: 1057d8aa74 ("device: Move device creation from netdev.c to event watch")
#0 0x000055555558ee5d in scan_notify (msg=0x55555560b640, user_data=0x0) at src/scan.c:1706
#1 0x00007ffff7f2c78c in ?? () from /usr/lib/libell.so.0
#2 0x00007ffff7f299ec in ?? () from /usr/lib/libell.so.0
#3 0x00007ffff7f28e4a in l_main_iterate () from /usr/lib/libell.so.0
#4 0x00007ffff7f28efc in l_main_run () from /usr/lib/libell.so.0
#5 0x00007ffff7f290b9 in l_main_run_with_signal () from /usr/lib/libell.so.0
#6 0x00005555555639c4 in main (argc=1, argv=0x7fffffffec18) at src/main.c:497
Save the source frame type in struct scan_bss as it may affect how some
of the data in the struct will be parsed. Also replace the P2P IE
payload data in that struct with a union containing pre-parsed p2p
attributes corresponding to the frame type.
This means users don't have to call the parsers in p2putil.c on that
data, which wouldn't have worked anyway because those parsers assume
input is the raw IE sequence rather than just the "payload".
All these functions free up the resources used by the struct but don't
free the struct itself (allowing it to be static) so rename the
functions to avoid confusion.
The kernel sends NL80211_ATTR_SCAN_START_TIME_TSF with CMD_TRIGGER and
RRM requires this value for beacon measurement reports.
The start time is parsed during CMD_TRIGGER and set into the scan request.
A getter was added to obtain this time value for an already triggered
scan.
After making the change, the SCAN_ABORTED case was cleaned up a bit to
remove the local scan_request usage in favor of the one used for all the
other cases.
Create and destroy the device state struct and the DBus interfaces in a
way more similar to the Station, AdHoc and AP interfaces. Drop
netdev_get_device() and the device specific code in netdev that as far
as I can tell wasn't needed.
Check the iftype before registering ANQP on new interface.
Not that the check here and in rrm.c (which already checks the iftype)
may need to be extended to run on NETDEV_WATCH_EVENT_UP because a device
could be created with a different iftype and then have the iftype changed
before powering up.
The RCPI value was using floating point values as per the spec. But instead
we can just use the signal strength coming from the kernel in mili mdm and
scale the hard coded values by a factor of 100.
Beacon requests can specify a scan duration, and set a flag which makes
this duration mandatory. The kernel supports both these values for scan
requests so we no longer need to reject requests which contain these.
Drivers which do not support EXT_FEATURE_SET_SCAN_DWELL will ignore the
duration value, but if duration mandatory is set we must reject the
request.
The kernel allows a scan duration and duration mandatory flag to be
set in scan requests. RRM requests can contain these values so they
have been added to scan_parameters.
Scanning with drivers which do not support EXT_FEATURE_SET_SCAN_DWELL
will not include these values in scan requests.
If a scan is requested during the middle of a connection we should
return busy instead of attempting the scan. The kernel ends up coming
back with not supported in this case, which is misleading and
difficult to debug.
The module framework was changed to call the module exit functions in
the reverse order as the init functions. This uncovered/caused known
networks to try and free the network_info structures after hotspot had
already freed them. Since known networks clean up the network_info's
anyways, we don't actually need hotspot to do any cleanup.
Apparently the intention was for the dependent module's name to appear
in the variable name resulting from using IWD_MODULE_DEPENDS, so the
dependencies all have unique names (apparently not critical).
Despite that PEAPv0 spec indicates that TLS tunnel needs to be torn
down after the transmission of a secure Result response, some servers
treat this TLS close alert as a failure. This patch changes the above
behavior to explicitly torn the tunnel only in the case of
authentication failure and leave it open after the success.
The previous refactoring somehow changed the 'Settings' section name
into 'General'
Fixes: ac53239109 ("doc: Split network configuration description into separate manpage")
This module takes care of radio measurements which an AP can request.
There are many types of requests, and for now only beacon requests
are supported.
IWD will filter certain types of beacon requests that are NOT
supported:
- AP channel reports. Only single channel requests will be supported
- Autonomous measurements. Only direct requests will be supported.
IWD will not accept requets to trigger reports under certain
conditions (SNR/RSSI thresholds, etc.)
- Timed measurements. Only immediate measurements will be performed.
The accuracy for timed measurements cannot be reliably guaranteed
due to kernel scheduling/queues.
- Full reporting detail. The AP can request the STA return the full
set of IEs in a beacon. IWD does not currently save all IEs, plus
there is quite a bit of complexity involved as certain IEs get
truncated, and there are other length limitations.
There are other limitations not specific to beacon requests:
- IWD will support single measurement requests per report. Multiple
measurement request IEs can be included, but the reports will be
sent out separately.
- IWD will limit the number of requests it responds to in a given
amount of time. As it stands now this is hard coded to 2 requests
per second maximum. This will prevent DoS attacks.
- IWD will not accept any measurement requests from APs it is not
connected to, and will not accept any requests until connected.
For Radio Resource Management (RRM) we will need access to the currently
connected BSS as well as the last scan results in order to do certain
kinds of requested measurements.
netdev_connect can achieve the same effect as netdev_connect_wsc but is
more flexible as it allows us to supply additional association IEs. We
will need this capability to make P2P connections. This way we're also
moving the WSC-specific bits to wsc.c from the crowded netdev.c.
On EAP events, call the handshake_event handler with the new event type
HANDSHAKE_EVENT_EAP_NOTIFY isntead of the eapol_event callback.
This allows the handler to be set before calling
netdev_connect/netdev_connect_wsc. It's also in theory more type-safe
because we don't need the cast in netdev_connect_wsc anymore.
Convert the handshake event callback type to use variable argument
list to allow for more flexibility in event-specific arguments
passed to the callbacks.
Note the uint16_t reason code is promoted to an int when using variable
arguments so va_arg(args, int) has to be used.
no_cck_rates is set in the scan parameters generally to make sure
that the Probe Request frames are not sent at any of the 802.11b
rates during active scans. With this patch we also omit those rates
from the Supported Rates IEs, which is required by the p2p spec and
also matches our flag's name.
The current logic did not make sure that each entry provided was
actually parsed. Also add a sanity check to make sure that no duplicate
parsing occurs.
When updating the network ranking there was a potential out of bounds
array access. The condition was if known_network_offset returned a
negative value, indicating the known network was not found. Since
network->info is only set for known networks this should not ever
happen as network->info is checked prior.
Though this is likely impossible, knownnetworks is complex enough that
its better to just be paranoid and put an L_WARN_ON to check the
return.
Since the property Autoconnect was renamed to AutoConnect, change the
Autoconnect setting to match.
For now we still allow the legacy name to be used here, but a warning is
printed to remind users to update.
Relax the pre-check for local user certificate. Before we used to check
that the CA provided (if any) was used to verify both the peer identity
and the local certificate chain. However, there seem to be networks
that use different CAs to sign AP/Radius certificates and certificates
issued to users.
Drop the ca_certs argument from l_certchain_verify, but keep the call
there to make sure the certificate chain is indeed a chain as a sanity
check.
The commit/confirm processing was incorrectly subtracting 2 from
the length when they should be subtracting 6. As with the other
similar change, the length is validated with mpdu_validate so
subtracting 6 will not cause an overflow.
This function was returning a boolean and the expected return was
a signed integer. Since this function actually returned false in
all cases the check for a success (0) return always worked.
The comment about the 'standard code path' was removed as this is
no longer valid.
If an authentication frame of length <= 5 is sent sae will overflow an
integer. The original cause of this was due to incorrectly using the
sizeof(struct mmpdu_header). The header can be either 24 or 28 bytes
depending on fc.order. sizeof does not account for this so 28 is always
the calculated length.
This, in addition to hostapd not including a group number when rejecting,
cause this erroneous length calculation to be worked around as seen in
the removed comment. The comment is still valid (and described again
in another location) but the actual check for len == 4 is not correct.
To fix this we now rely on mpdu_validate to check that the authentication
frame is valid, and then subtract the actual header length using
mmpdu_header_len rather than sizeof. Doing this lets us also remove the
length check since it was validated previously.
A recent change checked the return value of ie_parse_rsne_from_data
inside the ptk 1/4 handler. This seemed safe, but actually caused
the eapol unit test to fail.
The reason was because eapol was parsing the IEs assuming they were
an RSN, when they could be a WPA IE (WPA1 not WPA2). The WPA case
does not end up using the rsn_info at all, so having rsn_info
uninitialized did not pose a problem. After adding the return value
check it was found this fails every time for WPA1.
Since the rsn_info is not needed for WPA1 we can only do the RSN
parse for WPA2 and leave rsn_info uninitialized.
The intent here was to validate that the frequency is a multiple of 5
and lies in a certain range. Somehow the channel was checked for being
a multiple of 5 instead.
The logic here intended to check whether all required attributes were
available. However, it set the parse_error to true instead of
have_required to false as intended.
Replace uses of strcpy by the safer l_strlcpy. Note that both of these
functions can only be called with a buffer of max 253 bytes (the
identity string), so this is purely a precautionary measure.
Technically there's no problem here as l_queue_remove does not
dereference the pointer. Still, it confuses certain static analysis
tools in the current form. Reordering this will not change the behavior
at all.
This was refactored to set the mtu via __eap_set_config rather than
passing the MTU into eap_init. This makes eap work in a similar fashion
as eapol (i.e. __eapol_set_config).
If __eap_set_config is not used, the MTU will be set to 1020, which is
the same as previously passing 0 to eap_init.
Since iwd_modules_init is now defered until nl80211_appeared, we can
assume the nl80211 object is available. This removes the need for
netdev_set_nl80211 completely.
In preparation for integrating IWD_MODULE into modules which require
nl80211 we move the module init into the nl80211_appeared callback.
This will guarentee that the nl80211 is available during module init
and allow modules to get their own copy of nl80211 rather than needing
a set function (e.g. netdev_set_nl80211).
Since the dbus name request callback happens before this as well any
dbus module can also use IWD_MODULE and simply assume the dbus object
is ready.
plugin_init was also deferred to nl80211_appeared since some plugins
depend on modules being initialized.
Converts agent into an IWD module. This removes the dbus dependency
on agent. Since dbus is initialized very early we can assume
dbus_get_bus is going to return a valid object.
Previously, station state 'connected' used to identify an interface associated
with AP. With the introduction of netconfig, an interface is assumed to be
connected after the IP addresses have been assigned to it. If netconfig is
disabled, the behavior remains unchanged.
Refactoring was required to allow for embedded certs. The existing
eap_tls_state object was changed to hold the cert types (l_queue,
l_certchain, l_key) rather than the file path, since there may not
actually be separate PEM files.
Care was taken to properly manage the memory of these objects.
Since the TLS object takes ownership when setting auth data or the
CA certs all error cases must be handled properly to free these
objects after they are loaded and in addition they must be set to
NULL so that the cleanup doesn't double free them.
If everything goes to plan, we load all the PEMs in settings_load,
provide these objects to the TLS APIs, and then NULL out the
pointers (TLS now owns this memory). If anything fails between
settings_load and l_tls_start we must free these objects.
A special format must be used to indicate that a PEM is embedded
inside the settings file. First, the l_settings format should be
followed for the PEM itself, e.g.
[@pem@my_ca_cert]
<CA Cert data>
This PEM can then be referenced by "embed:my_ca_cert", e.g.
EAP-TLS-CACert=embed:my_ca_cert
Any other value not starting with "embed:" will be treated as a file
path.
The IPv6 default route needs to be explicitly revoked. Unlike in IPv4,
there is no SRC address associated with the route and it will not be
removed on address removal.
The network configuration options for IPv6 are grouped under [IPv6]
and include the following:
ip= ADDRESS/PREFIX
gateway=ADDRESS
dns=ADDRESS
The placeholders for DHCPv6 are placed along the way and marked
as TODO items.
Previously, netconfig_ipv4_select_and_install was used to install
addresses on initial connection to a network and after we have roamed.
Now for the after roaming connection scenario we have
netconfig_reconfigure. Remove roaming related code from
netconfig_ipv4_select_and_install
As part of the de-coupling from station object, switch all of
the network settings inquiries to use active_settings. active_settings
are set with netconfig_configure by the owner of netconfig object
and removed with netconfig_reset once network disconnects.
Instead of relying on station state changed signal, netconfig
introduces three new API calls to configure, re-configure and
reset the network configurations. The owner of netconfig object
is responsible for initiating the re-configuration of the device
depending on its state.
As a first step to enable the usage of netconfig in ead and
prospective transition to be a part of ell, the public API for
creation and destruction of the netconfig objects has been
renamed and changed. Instead of hiding the netconfig objects inside
of netconfig module, the object is now passed back to the caller.
The internal queue of netconfig objects remains untouched, due
to limitations in ell’s implementation of rtnl. After the proper
changes are done to ell, netconfig_list is expected to be removed
from netconfig module.
A NEW_WIPHY event may not always contain all the information about a
given phy, but GET_WIPHY will. In order to get everything we must
mimic the behavior done during initalization and dump both wiphy
and interfaces when a NEW_WIPHY comes in.
Now, any NEW_WIPHY event will initialize a wiphy, but then do a
GET_WIPHY/GET_INTERFACE to obtain all the information. Because of
this we can ignore any NEW_INTERFACE notifications since we are
dumping the interface anyways.
Once some kernel changes get merged we wont need to do this anymore
so long as the 'full' NEW_WIPHY feature is supported.
If the AP sent us the plain passphrase we can now store that rather
than generating the PSK. This will allow WPA3 to work properly when
WPA3 + WSC is implemented.
This lets other modules (like WSC) to set a plain text passphrase
as opposed to only allowing a PSK to be set. network_get_psk was
also updated to generate a PSK on-the-fly if required. Since WPA3
requires the raw passphrase to work, it makes sense to just store
the passphrase if we have it.
If neighbor reports are unavailable, or the report yielded no
results we can quickly scan for only known frequencies. This
changes the original behavior where we would do a full scan
in this case.
This password key was deprecated in favor of the common EAP-Password
key. Its been about a year so we are now removing support entirely
for EAP-PWD-Password.
Gets a newly created scan_freq_set containing the most recent
frequencies for the network. The currently connected BSS frequency
(passed as a parameters) will not be included in the set.
Since the UUID was being generated purely on the file path, it
would never change for a given network (unless the SSID/name changed).
In the future we would like to use this unique UUID to generate a
MAC per-SSID, and if that network is forgotten we also want the UUID
to change next time the network is connected to.
Rather than only using the file path, the mtime can also be fed into
the UUID generation. Since the mtime would be changed after forgetting
and re-adding a known network we will get a new UUID.
Now, whenever a known network is removed, we lookup the UUID we have
in network_info and remove that entry in the settings file and
sync the frequency file.
The UUID was being generated every time we synced which is wasteful.
Instead we can track the UUID inside network_info and only generate
it once when needed.
Two new network_info APIs were added:
network_info_set_uuid
network_info_get_uuid
The setter is used when the frequency file is loaded. If a valid UUID
is found in the frequency file this UUID is set and used.
network_info_get_uuid will not just get the UUID, but actually generate
it if one has not been set yet. This will allow other modules to
get/generate the UUID if one has no been loaded from the frequency
file.
The QoS Map can come in either as a management frame or via the
Associate Response. In either case this IE simply needs to be
forwarded back to the kernel.
The extended capability bits were not being set properly inside
wiphy. Since we build the IE after the wiphy dump the first 2
bytes are the IE type and length. The way we were setting the bits
did not take this into account and were actually setting the
completely wrong bits.
The known frequency file was being loaded at the end of the known
networks initialization routine. This allowed all known networks
to be properly loaded, but since hotspot depends on known networks,
its initalization would be run afterwards meaning the frequency
loading would not have been finding any hotspot networks.
To fix this a new module was added inside known networks which
depends on hotspot. This means that first known networks will
initialize, then hotspot, then the frequency file would be loaded.
The current format for the .known_networks.freq file had a hidden
limitation of not being able to handle SSID's with some special
characters. Since the provisioning file path was used as the
group name the filename was limited to only characters supported
by l_settings groups, which conflicted with allowable SSID
characters.
Instead we can generate a unique UUID for each network and use
this as the group. For this particular case the group does not
really matter, so long as its unique. But we can utilize this unique
UUID for other purposes, including using it as a seed for changing
the MAC address per-connection in the future.
The .known_networks.freq file will now have the following format:
[<UUID>]
name=/path/to/provisioning/file
list= XXXX YYYY ZZZZ
The existing frequency syncing was done when IWD closes. Instead we
can sync as networks are connected to or promoted to known which
will keep the FS more up to date. This also allows hotspot networks
to use the known frequency file.
This API will sync the known frequencies of a network_info object
to disk. This will allow network to sync known frequencies as
known networks are added, rather that when IWD closes.
Since this will result in more frequent syncing that before, the
known_freqs settings pointer was moved globally in knownnetworks.c
as to only parse the file one time rather than on every sync.
Some of the EAP-PEAP server implementations seem to require a
cleartext ACK for the tunneled EAP-Success message similar to EAP-TLS
specification, instead of simply shutting down the tunnel like
EAP-PEAPv1 requires.
ACKing the tunneled EAP-Success seems also to work for implementations
which were relying on the tunnel close event.
create_dirs was dependent on the path ending in '/' to create the
full path. The hotspot code did not include a '/' at the end so
it was not getting created, which prevented the hotspot module
from initializing.
Station was building up the HS20 elements manually. Now we can
use this new API and let network take care of the complexity
of building network specific vendor IEs.
This op builds up the vendor IEs required for hotspot 2.0. The
version, and optionally the RC are provided in order to correctly
build the HS20 Indication Element and RC Selection element.
The HS20 module had its own getter for returning the matched roaming
consortium. Since we already have the network_info op for matching
we might as well return the matched RC rather than just a bool. This
allows the RC to be included in (Re)Association without the need for
a specific getter.
When performing a fast transition to another OPEN network the RSN
element won't be there and therefore the bss->rsne is gonna be NULL.
Fix crash by not accessing the rsne member when performing a fast
transition to an AP that doe snot advertise any RSN IE.
Crash caught with gdb:
src/station.c:station_transition_start() 186, target 34:8f:27:2f:b8:fc
Program received signal SIGSEGV, Segmentation fault.
handshake_state_set_authenticator_ie (s=0x555555626eb0, ie=0x0) at src/handshake.c:163
163 s->authenticator_ie = l_memdup(ie, ie[1] + 2u);
(gdb) bt
#0 handshake_state_set_authenticator_ie (s=0x555555626eb0, ie=0x0) at src/handshake.c:163
#1 0x0000555555561a98 in fast_transition (netdev=0x55555562fbe0, target_bss=0x55555561f4a0,
over_air=over_air@entry=true, cb=0x55555556d5b0 <station_fast_transition_cb>) at src/netdev.c:3164
#2 0x0000555555565dfd in netdev_fast_transition (netdev=<optimized out>, target_bss=<optimized out>,
cb=<optimized out>) at src/netdev.c:3232
#3 0x000055555556ccbd in station_transition_start (bss=0x55555561f4a0, station=0x555555617da0)
at src/station.c:1261
#4 station_roam_scan_notify (err=<optimized out>, bss_list=<optimized out>, userdata=0x555555617da0)
at src/station.c:1444
#5 0x0000555555579560 in scan_finished (sc=0x55555562bf80, err=err@entry=0, bss_list=0x55555561bd90,
sr=0x555555626b30, wiphy=<optimized out>) at src/scan.c:1234
#6 0x0000555555579620 in get_scan_done (user=0x555555618920) at src/scan.c:1264
#7 0x00005555555abd23 in destroy_request (data=0x55555561b000) at ell/genl.c:673
#8 0x00005555555ac129 in process_unicast (nlmsg=0x7fffffffc310, genl=0x55555560b7a0) at ell/genl.c:940
#9 received_data (io=<optimized out>, user_data=0x55555560b7a0) at ell/genl.c:1039
#10 0x00005555555a8aa3 in io_callback (fd=<optimized out>, events=1, user_data=0x55555560b840)
at ell/io.c:126
#11 0x00005555555a7ccd in l_main_iterate (timeout=<optimized out>) at ell/main.c:473
#12 0x00005555555a7d9c in l_main_run () at ell/main.c:520
#13 l_main_run () at ell/main.c:502
#14 0x00005555555a7fac in l_main_run_with_signal (callback=<optimized out>, user_data=0x0)
at ell/main.c:642
#15 0x000055555555e5b8 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:519
After wsc_store_credentials, wsc_try_credentials is called which
sets the PSK obtained via the protocol. After the known network
refactor network_settings_load was changed to depend on the
network_info->open() call. Since there is no known network for
this initial WSC connection this always fails and the PSK is not
set into the network object (and the connection is failed).
In this case if network_settings_load fails we can just create
an empty settings object to be filled later.
known_network_update was being used to both update and create known
networks as they appeared on the file system. Hotspot needs updating
capabilities so known_network_update was exposed and updated with
one major difference; it no longer can be used to create new known
networks. For creation, a new API was added (known_network_new)
which will create and add to the queue.
Since hotspot networks may require ANQP the autoconnect loop needed to
be delayed until after the ANQP results came back and the network
objects were updated. If there are hotspot networks in range ANQP will
be performed and once complete autoconnect will begin for all networks
including hotspots. If no hotspots are in range autoconnect will
proceed as it always has.
Note: Assuming hotspots are in range this will introduce some delay
in autoconnecting to any network since ANQP must come back. The full
plan is to intellegently decide when and when not to do ANQP in order
to minimize delays but since ANQP is disabled by default the behavior
introduced with this patch is acceptable.
The remove op was being called inside known_networks_remove, which only
gets called from L_DIR_WATCH events. In this case the actual provisioning
has already been removed. Calling remove() again causes the op
implementation to then try and remove the file that no longer exists.
Valgrind does not like uninitialized bytes used in a syscall. In this
case the buffer is an out buffer but since valgrind doesn't know that
it complains. Initializing to zero fixes the warning:
Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
at 0x5162C4D: send (send.c:28)
by 0x457AF4: l_checksum_update (checksum.c:319)
by 0x43C03C: eap_wsc_handle_m2 (eap-wsc.c:842)
by 0x43CD33: eap_wsc_handle_request (eap-wsc.c:1048)
by 0x43A3A7: __eap_handle_request.part.0 (eap.c:266)
by 0x41A426: eapol_rx_packet.part.12 (eapol.c:2262)
by 0x41B536: __eapol_rx_packet (eapol.c:2650)
by 0x407C80: netdev_control_port_frame_event (netdev.c:3542)
by 0x407C80: netdev_unicast_notify (netdev.c:3684)
by 0x4598C5: dispatch_unicast_watches (genl.c:899)
by 0x4598C5: process_unicast (genl.c:918)
by 0x4598C5: received_data (genl.c:1039)
by 0x456452: io_callback (io.c:126)
by 0x45569D: l_main_iterate (main.c:473)
by 0x45576B: l_main_run (main.c:520)
Address 0x1ffeffe290 is on thread 1's stack
in frame #2, created by eap_wsc_handle_m2 (eap-wsc.c:797)
We were not using or taking into account the noencrypt flag obtained
from the kernel via CONTROL_PORT events. For the most part this still
worked as the kernel would never include NO_ENCRYPT flag (due to a bug).
However, this was actually incorrect and led to loss of synchronization
between the AP and STA 4-Way handshake state machines when certain
packets were lost and had to be re-transmitted.
Allow users to provide a glob string that the contents of the server
certificate's subject DN should be matched against as a primitive
protection against rogue APs using certificates purchased from
commercial CAs trusted by the client. If the network uses an AP
certificate emitted by a commerical CA and the clients are configured
to trust those CAs so that the client configurations don't have to be
updated when the AP renews its certificate, this new option can be used
to check if the CN in the AP certificate's DN matches the known domain
name. This logic assumes that the commercial CAs provide enough
assurance that only the owner of the domain can buy a certificate with
that domain in the CN field.
The format of this option is similar to apple's TLSTrustedServerNames
and wpa_supplicant's domain_match/domain_suffix_match format, the exact
syntax is documented in ell/tls.c.
Some capability bits are required by the spec to be set for
probe requests for certain features (HS20, FILS, FT). Currently
these features work as-is, but depending on the hardware we may
be in violation of the spec if we assume the correct bits are
set when we get the wiphy dump.
Just to be safe we can explicity set these capability bits.
There are also two ways the kernel exposes these capabilities.
Per-type or globally. The hardware may expose one, or both of
these capability arrays. To combat this we are now always
creating a per-type capability array for stations. If the
wiphy dump has not produced a per-type capability array we
now create one based off the global capability array. That
way we can always assume there is a capability array for a
station iftype.
This will be seen in Probe Requests. More IEs can and should
be added here depending on the support in IWD. E.g. HS20 indication,
Interworking, HT/VHT IE's etc.
In order to implement get_name/get_type we need some value for the name
of the hotspot network. For simplicity we now require a 'Name' value
be provided inside the hotspot provisioning file. Eventually this may
change (e.g. obtained via ANQP).
Rather than using timespec directly, ELL has a convenient API
to get the elapsed microseconds as a uint64_t. This can then
be used with the other l_time_ APIs for comparison.
This patch removes timespec from network_info and updates
to use l_time_* API's for sorting.
These operations will allow the hotspot module to implement
matching HESSID, Roaming Consortium, and NAI realms. This offloads
the matching details into the hotspot module.
This way resolve_remove can be called once per interface and
remove IPv4 and IPv6 addresses at once.
In addition, this allows to remove the IP addresses and DNS
servers within the same main loop cycle. This will allow iwd
to make an attempt to remove the DNS servers on shutdown of iwd.
These two API's have been added to allow hotspot to add its
own networks to the known network list. This will allow any
added networks to behave exactly like they do now, including
all the dbus and watchlist functionality.
The known network APIs all revolved around the ssid/security matching
to do any operations on the provisioning file. In the near future
hotspot provisioning files (managed by hotspot.c) will be incorporated
into the known network list. Since these hotspot files do not use the
ssid as the file name hotspot.c will need other ways of matching.
This patch adds network_info_ops to the network object. This ops
structure will hold function pointers which operate on network_info
rather than ssid/security. This will allow hotspot and known networks
to both register their own operation routines.
For now open, touch, sync, remove, free, and get_path were added.
Wrappers were added for accessing these operations outside of
knownnetworks.c.
Isolate the known_frequency queue management to a function and place
that function in knownnetworks.c where it now belongs. Since we no
longer have network_info objects for unknown networks, only frequencies
for known networks are tracked
networks queue was intended to share basic network information between
multiple adapters running simultaneously. The network_info object was
also serving double duty to carry known network information. This made
things overly complicated and really didn't result in much savings.
This setup also made managing hotspot networks challenging as we would
have ended up with multiple network_info objects for each known hotspot
network.
So get rid of the networks queue and the is_known bit from the
network_info structure.
network_find_rank_index was used to find the offset of the selected
network_info among known networks so as to compute a modifier based on
the rankmod table. Instead of using known_networks_foreach for this,
moove it to knownnetworks.c where it can be coded and optimized
separately.
For now provide a simple for loop implementation.
Previously, the option PrivateDevices=true disabled access to
/dev/rfkill, which lead to:
'iwctl adapter phy0 set-property Powered {off|on}'
to fail.
This patch explicitly allows access to /dev/rfkill
src/rtnlutil.c: In function ‘rtnl_route_add’:
./ell/util.h:248:2: error: ‘rtmmsg’ may be used uninitialized in
this function [-Werror=maybe-uninitialized]
Instead of using a flag ipv4_static, just store the value of the rtm
protocol directly inside netconfig object. This allows us to simplify
the logic quite significantly and avoid repeating the conditional
expression needlessly
The routes are installed as a result of a successful installation
of the IP addresses. The gateway is fetched with netconfig_ipv4_get_gateway
helper function according to the origin of the installed IP address.
The route priority offset can be set in main.conf. The default value
of 300 is used if the offset isn’t set.
The API allows to add connected and gateway routes to the main
routing table.
rtnl_route_ipv4_add_gateway() is equivalent to the following
example 'ip route' command:
ip route add default via 10.0.0.1 dev wlan0 proto dhcp src 10.0.0.2 metric 339
rtnl_route_ipv4_add_connected() is equivalent to the following
example 'ip route' command:
sudo ip route add 10.0.0.0/24 dev wlan0 proto dhcp src 10.0.0.2 scope link
The 'ip route' output from the above commands looks as follows:
rtnl_route_ipv4_add_connected():
10.0.0.0/24 dev wlan0 proto dhcp scope link src 10.0.0.2
rtnl_route_ipv4_add_gateway():
default via 10.0.0.1 dev wlan0 proto dhcp src 10.0.0.2 metric 339
The DNS addresses are installed as a result of a successful
installation of the IP addresses. The DNS lists are fetched
with netconfig_ipv4_get_dns helper function according to the
origin of the installed IP address.
iwd reconfigures the wireless interfaces with respective
connection events. Each supported network protocol is
reconfigured. The address for each protocol is
selected as static or dynamic based on availability.
netconfig_ipv4_get_ifaddr helper function allows to fetch IPv4
addresses from static or dynamic sources. The origin of the addresses
is noted in 'ipv4_is_static' flag.
For (Re)Association the HS20 indication element was passed exactly as
it was found in the scan results. The spec defines what bits can be
set and what cannot when this IE is used in (Re)Association. Instead
of assuming the AP's IE conforms to the spec, we now parse the IE and
re-build it for use with (Re)Association.
Since the full IE is no longer used, it was removed from scan_bss, and
replaced with a bit for HS20 support (hs20_capable). This member is
now used the same as hs20_ie was.
The version parsed during scan results is now used when building the
(Re)Association IE.
The parser fully parses the IE and returns the version, Domain ID,
and PPS MO ID. This is meant to be used with an IE in scan results.
The builder only takes the version number, and assumes DGAF disabled,
and no Domain ID or PPS MO ID.
Previously, iwd used to throw net.connman.iwd.Busy when connection
attempt was made while connected. The new behavior allows iwd to
seamlessly disconnect from the connected network and attempt a new
connection.
Since NAI realms, Roaming Consortium and HESSID are defined in 802.11,
they are not a guarentee that the network is Hotspot 2.0. The indication
element in addition to these IE's gives a better idea of Hotspot 2.0
support. Now, when a BSS is added this is_hs20 boolean will get set to
true if the HS20 IE was found in the BSS.
Now, if is_hs20 is set AND one of NAI realms, roaming consortium, or
HESSID is set we know this is a hotspot 2.0 network.
It is possible for a zero-length anti-clogging token payload to cause
IWD to abort. If the length passed into sae_process_anti_clogging was
1, l_memdup would be called with a size of -1. This will cause malloc
to abort.
Fix this by checking for a minimum packet length and dropping the
packet if the length is too small.
The HS20 indication element should always be included during
(Re)Association per the spec. This removes the need for a
dedicated boolean, and now the hs20_ie can be used instead.
The hotspot spec specifically mentions the roaming consortium OI be
3 or 5 bytes long. This requirement also prevents potential buffer
overflows if the user were to configure a long roaming consortium OI.
If the scan was triggered and later aborted, make sure to reset the
triggered value when the CMD_NEW_SCAN_RESULTS event comes in.
src/station.c:station_enter_state() Old State: disconnected, new state: connecting
src/scan.c:scan_notify() Scan notification 33
src/station.c:station_netdev_event() Associating
src/scan.c:scan_notify() Scan notification 34
Aborting (signal 11) [/home/denkenz/iwd-master/src/iwd]
++++++++ backtrace ++++++++
#0 0x7efd4d6a2ef0 in /lib64/libc.so.6
#1 0x42b20d in scan_notify() at src/scan.c:1383
In the same fashion as the WSC WFA OUI, ie.[ch] will now expose the
other vendor OUIs to avoid duplication across multiple files in IWD
as well as used in iwmon.
P2P probe requests are to be sent at min 6.0 Mb/s using OFDM,
specifically the 802.11b rates are prohibited (section 2.4.1 in Wi-Fi
P2p Technical Spec v1.7), some of which use CCK modulation. This is
already the default for 5G but for 2.4G the drivers generally do this
if we set the NL80211_ATTR_TX_NO_CCK_RATE flags with
NL80211_CMD_TRIGGER_SCAN.
The length check was incorrectly assuming that PPS MO ID or
ANQP Domain ID would be present in the IE. Both these are optional
and without then the minimum length is 5 bytes, not 7.
Per the hotspot 2.0 spec, if a matching roaming consortium OI is
found it should be added to the (Re)Association request. vendor_ies
can now be provided to netdev_connect, which get appended to the IE
attribute.
This API will attempt to find a matching roaming consortium OI
if present in the config file. A single matching OI is returned
or NULL if one was not found.
Hotspot 2.0 network providers allow 'roaming' between a users home
network and other providers networks, assuming they are part of the
same roaming consortium. The roaming consortium is advertised as an
IE in beacon/probe frames.
In terms of the hotspot config files this is similar to HESSID, where
if the AP advertises the roaming consortium IE, and the config file
matches we do not need to do ANQP in order to connect.
This is duplicated when the first scan_bss is added to a network
object that contains the IE. Any future BSS's added will not re-add
the IE. Its assumed that all BSS's under a network will contain the
same roaming consortium OIs.
Parses up to 3 (the max) roaming consortium OIs out of the roaming
consortium IE. If more OIs are available via ANQP the 'num_anqp_out'
value will be set to indicate how many more OIs are available.
Builds according to the hotspot 2.0 spec using the vendor specific
IE.
Declare structures to hold the parsed contents of the P2P IEs and WSC
IEs in P2P-related frames and add functions to free memory used by
those structures.
Define structs and types for most P2P attributes and p2p_parse_attrs
similar to wsc_parse_attrs -- a generic parser for attributes in a P2P
IE payload. This parser may write into the provided buffer even on
error but it's private to p2putil.c. The local callers will take care
of keeping the user-provided buffers untouched on error.
Add a utility for building the simplified WSC IEs used in P2P action
frames and public action frames. Only three types of WSC attributes are
mandatory in those frames (but different subsets are needed by different
frame types) so add a single utility for building those IEs. We may
need to add some more optional attributes to those IEs later.
The ifindex is used to index the netdevs in the system (wlan, ethernet,
etc.) but we can also do wifi scanning on interfaces that have no
corresponding netdev object, like the P2P-device virtual interfaces.
Use the wdev id's to reference interfaces, the nl80211 api doesn't care
whether we use a NL80211_ATTR_IFINDEX or NL80211_ATTR_WDEV. Only
wireless interfaces have a wdev id.
Save the actual cmd_id returned from l_genl_family_dump and zero it in
the get_scan_done. There's no need to zero it in scan_cancel because
get_scan_done gets called automatically.
Store the scan_context pointer in scan_results directly instead of
storing the ifindex. We now cancel ongoing GET_SCAN commands when the
scan_context is being freed so there's no point going through the extra
step of looking up the scan_context by ifindex inside the command
callback to guard against non-existent scan_contexts.
method.ops is NULL, which causes method.ops->exit to crash. This
adds a check that method.ops is not NULL before dereferencing.
Fixes:
Aborting (signal 11) [/home/jprestwo/iwd/src/iwd]
++++++++ backtrace ++++++++
0 0x7f016b59cf20 in /lib/x86_64-linux-gnu/libc.so.6
1 0x432057 in resolve_exit() at /home/jprestwo/iwd/src/resolve.c:295
2 0x403b61 in iwd_modules_exit() at /home/jprestwo/iwd/src/main.c:195
3 0x7f016b57fb97 in /lib/x86_64-linux-gnu/libc.so.6
+++++++++++++++++++++++++++
The original idea was to allow the provisioning file to include HESSID
without the NAIRealmNames. Configuring this way would allow for ANQP
to be skipped completely, assuming the AP advertises its HESSID.
The way the code was written still required NAIRealmNames to be
provided in the provisioning file.
The framework enables the service specific implementations
to provide its own variations for the DNS installation tasks.
The selection of the address resolution service can be done
through dns_resolve_method setting.
The module is responsible for the configuration of the address
resolution services. It will consist of the multiple service
specific plugins such as: systemd-resolved plugin, dnsmasq
plugin, etc.
If supported by the driver, we can create an interface directly with a
random MAC if configured to do so. If the driver does not have this
capability, then tell netdev to perform the necessary logic as part of
the interface initialization procedure.
#0 0x7f5e25e71930 in /lib64/libc.so.6
#1 0x446faa in hs20_config_free() at src/hotspot.c:63
#2 0x469542 in l_queue_clear() at ell/queue.c:109
#3 0x4694e7 in l_queue_destroy() at ell/queue.c:83
#4 0x4475c1 in hotspot_exit() at src/hotspot.c:273
#5 0x403170 in iwd_modules_exit() at src/main.c:195
#6 0x404085 in main() at src/main.c:531
#7 0x7f5e25e5cbde in /lib64/libc.so.6
Regulatory domain management is now completely handled by the kernel, so
iwd doesn't really need to query or be aware of changes to this. This
may change in the future, but for now this code has not been used and
can be safely gotten rid of.
After a scan, station can now pause future scans and start ANQP requests
to discover Hotspot's NAI realm. This lets us check if the AP's NAI realm
matches any stored hotspot configuration files. If so we can connect to
this network. If the network provides an HESSID and a matching one is
found in a hotspot provisioning file we can skip ANQP and directly connect
as this is expected to be our 'home network'
The actual ANQP request was handled by netdev, but in the case of P2P
their may be no netdev. For this reason all functionality needed for
an ANQP request has been moved into anqp.c. There are still a few netdev
references, which need to be removed when P2P is introduced. Leaving them
in for now as its still going to work as a first pass implementation
The initial ANQP parser design did not work well with how the hotspot
implementation was turning out. For one, much care was taken into parsing
the EAP credentials which are not really required. The assumption is
that any hotspot network will already be provisioned, so checking that
the EAP parameters match is a bit overkill. Instead only the NAI Realms
will be checked. This greatly simplifies the NAI realm parser, as now it
can just return a string list of realms instead of the full EAP
credential info.
This module will be in charge of managing Hotspot provisioning files
stored under the .hotspot/ directory. This includes a dir watch to
handle file changes/removal as well as an API to match a network
object to a hotspot provisioning file.
Hotspot networks are supposed to include an HESSID in the scan
results. This is more or less an identifier for the overall
network. In addition, the NAI Realms can be obtained via ANQP
and should be the same for each BSS. Since both HESSID and NAI
realms should be the same for a given network in range we can
store these values in the network object itself. This also allows
us to easily find hotspot configuration files by looking at
the HESSID/NAI Realms directly in the network object as opposed
to individual scan_bss's.
In order to do ANQP efficiently IWD needs the ability to suspend scanning
temporarily. This is because both scanning and ANQP go offchannel and must
remain off channel for some amount of time. This cannot be done
simultaneously and if e.g. ANQP is requested after a scan is already
pending, the kernel will wait till that scan finishes before sending out
the frame.
Use memset instead. explicit_bzero should only be used when we're
wiping a secret just prior to the encopassing storage being freed. The
compiler would usually optimize away the memset, leaving the secrets
around.
In rtnlutil we're simply zeroing the structure prior to filling it, so
the use of explicit_bzero is not needed and brings confusion to the
reader since no secrets are being wiped.
netconfig is interested in three station states: connected,
disconnected and connected after it has roamed. On connected
it tries to obtain a new DHCP lease, on disconnected it stops
the DHCP client and discards all addresses from interface, on
connected after roaming it will try to request a previously
issued address.
iwd keeps track of the addresses assigned to the managed
interfaces. The list of assigned IPv4/IPv6 addresses is stored
in ifaddr_list inside of netconfig. The tracking of the IP
addresses will help to remove them from an interface once they
are no longer valid.
netconfig module will be responsible for the orchestration
of the network configuration with the IP addresses.
iwd creates one netconfig structure per interface index.
The purpose of this struct is to hold all of the interface
related addressing states such as: assigned dhcp
clients, known addresses, routes, etc.
A not-yet-merged kernel patch will enable the FRAME_WAIT_CANCEL
event to be emitted when a CMD_FRAME duration expires. This can
shortcut the ridiculously long timeout that is required making
GAS requests with no response drastically quicker to handle.
This adds a new API netdev_anqp_request which will send out a GAS
request, parses the GAS portion of the response and forwards the
ANQP response to the callers callback.
This IE tells us what Advertisement Protocols the AP supports. This
is only here to look for ANQP support, so all this does is iterate
through all other Advertisement Protocol tuples looking for ANQP.
If found, anqp_capable is set in the scan_bss
Currently these are geared to support the WiFi Alliance Hotspot 2.0
ANQP elements, which all fall under the vendor specific ANQP element.
anqp_iter_next behaves similar to the genl parsers, where the id, length
and data will be returned as out parameters. Currently there is only
vendor support for Hotspot 2.0. anqp_iter_is_hs20 can be used to setup
the subtype, length, and data pointer to parse any Hotspot 2.0 ANQP
elements. From here the subtype can be checked and a vendor specific
parser for that subtype can be used to parse the data, e.g.
hs20_parse_osu_provider_nai.
The vendor specific IE was being parsed only to check if the AP supported
WPA, which used a Microsoft OUI. Hotspot/OSEN uses neither WPA or RSN
(although its nearly identical to RSN) so the we also need to check for
this Wifi-Alliance OUI and set bss->osen (new) if found.
The OSEN AKM uses the vendor specific IE, so when finding the RSNE
element we need to handle it specially to ensure that its both
a vendor specific element and it matches the WFA OUI since other
vendor specific elements may be included.
The OSEN AKM is nearly identical to the RSN IE, but differs slightly.
For one, OSEN is encapsulated into the vendor specific IE, and includes
the WFA OUI before the 'normal' RSN elements. OSEN also does not include
a WPA version, since its not technically WPA/WPA2.
Some of the RSN parsing was made common so both RSN/OSEN parsing could
use it.
The handshake object had 4 setters for authenticator/supplicant IE.
Since the IE ultimately gets put into the same buffer, there really
only needs to be a single setter for authenticator/supplicant. The
handshake object can deal with parsing to decide what kind of IE it
is (WPA or RSN).
The Hotspot 2.0 spec introduces 'Anonymous EAP-TLS' as a new EAP method
to be used with OSEN/Hotspot. The protocol details of this aren't
relevant to this patch, but one major difference is that it uses the
expanded EAP type rather than the TLS type. Since the common TLS code
was written with only EAP_TYPE_TLS in mind the vendor ID/type cause the
EAP packet to be malformed when using the expanded EAP type.
To handle this the common TLS code now checks the EAP type, and if its
expanded we shift the payload 7 bytes further to account for the extra
header data.
802.11 defines GAS (generic advertisement service) which can be used
to query supported advertisement protocols from an AP before
authentication/association. Hotspot/OSEN only care about the ANQP
protocol, but the way the IE is structured potentially requires
iterating through several tuples before you reach the ANQP protocol
identifier. Because of this we define all protocol identifiers.
This adds some checks for the FT_OVER_FILS AKMs in station and netdev
allowing the FILS-FT AKMs to be selected during a connection.
Inside netdev_connect_event we actually have to skip parsing the IEs
because FILS itself takes care of this (needs to handle them specially)
FILS unfortunately is a special case when it comes to fast transition.
We have to process the FT IEs internally since we cannot trigger the
same initial mobility association code path (via netdev).
FT over FILS-SHA384 uses a 24 byte FT MIC rather than the 16 byte MIC
used for all other AKMs. This change allows both the FT builder/parser
to handle both lengths of MIC. The mic length is now passed directly
into ie_parse_fast_bss_transition and ie_build_fast_bss_transition
FILS-FT is a special case with respect to the PTK keys. The KCK getter
was updated to handle both FT-FILS AKMs, by returning the offset in
the PTK to the special KCK generated during FILS. A getter for the KCK
length was added, which handles the SHA384 variant. The PTK size was
also updated since FILS-FT can generate an additional 56 bytes of PTK
ifaddr is not guaranteed to be initialized, I'm not sure why there was
no compiler warning. Also replace a | with a || for boolean conditions
and merge the wiphy check with that line.
When handling a scan finished event for a scan we haven't started check
that we were not halfway through a scan request that would have its
results flushed by the external scan.
FT-over-DS is a way to do a Fast BSS Transition using action frames for
the authenticate step. This allows a station to start a fast transition
to a target AP while still being connected to the original AP. This,
in theory, can result in less carrier downtime.
The existing ft_sm_new was removed, and two new constructors were added;
one for over-air, and another for over-ds. The internals of ft.c mostly
remain the same. A flag to distinguish between air/ds was added along
with a new parser to parse the action frames rather than authenticate
frames. The IE parsing is identical.
Netdev now just initializes the auth-proto differently depending on if
its doing over-air or over-ds. A new TX authenticate function was added
and used for over-ds. This will send out the IEs from ft.c with an
FT Request action frame.
The FT Response action frame is then recieved from the AP and fed into
the auth-proto state machine. After this point ft-over-ds behaves the
same as ft-over-air (associate to the target AP).
Some simple code was added in station.c to determine if over-air or
over-ds should be used. FT-over-DS can be beneficial in cases where the
AP is directing us to roam, or if the RSSI falls below a threshold.
It should not be used if we have lost communication to the AP all
(beacon lost) as it only works while we can still talk to the original
AP.
To support FT-over-DS this API needed some slight modifications:
- Instead of setting the DA to netdev->handshake->aa, it is just set to
the same address as the 'to' parameter. The kernel actually requires
and checks for these addresses to match. All occurences were passing
the handshake->aa anyways so this change should have no adverse
affects; and its actually required by ft-over-ds to pass in the
previous BSSID, so hard coding handshake->aa will not work.
- The frequency is is also passed in now, as ft-over-ds needs to use
the frequency of the currently connected AP (netdev->frequency get
set to the new target in netdev_fast_transition. Previous frequency
is also saved now).
- A new vector variant (netdev_send_action_framev) was added as well
to support sending out the FT Request action frame since the FT
TX authenticate function provides an iovec of the IEs. The existing
function was already having to prepend the action frame header to
the body, so its not any more or less copying to do the same thing
with an iovec instead.
Since FT already handles processing the FT IE's (and building for
associate) it didn't make sense to have all the IE building inside
netdev_build_cmd_ft_authenticate. Instead this logic was moved into
ft.c, and an iovec is now passed from FT into
netdev_ft_tx_authenticate. This leaves the netdev command builder
unburdened by the details of FT, as well as prepares for FT-over-DS.
Blacklist some drivers known to crash when interfaces are deleted or
created so that we don't even attempt that before falling back to using
the default interface.
Read the driver name for each wiphy from sysfs if available. I didn't
find a better way to obtain the driver name for a phy than by reading
the dir name that the "driver" symlink points at. For an existing
netdev this can be done using the SIOCETHTOOL ioctl.
manager_interface_dump_done would use manager_create_interfaces() at the
end of the loop iterating over pending_wiphys. To prevent it from
crashing make sure manager_create_interfaces never frees the pending
wiphy state and instead make the caller check whether it needs to be
freed so it can be done safely inside loops.
Instead of having two separate types of scans make the periodic scan
logic a layer on top of the one-off scan requests, with minimum code to
account for the lower priority of those scans and the fact that periodic
scans also receive results from external scans. Also try to simplify
the code for both the periodic and one-off scans. In the SCAN_RESULTS
and SCAN_ABORT add more complete checks of the current request's state
so we avoid some existing crashes related to external scans.
scan_send_next_cmd and start_next_scan_request are now just one function
since their funcionality was similar and start_next_scan_request is used
everywhere. Also the state after the trigger command receives an EBUSY
is now the same as when a new scan is on top of the queue so we have
fewer situations to consider.
This code still does not account for fragmented scans where an external
scan between two or our fragments flushes the results and we lose some
of the results, or for fragmented scans that take over 30s and the
kernel expires some results (both situations are unlikely.)
In both netdev_{authenticate,associate}_event there is no need to check
for in_ft at the start since netdev->ap will always be set if in_ft is
set.
There was also no need to set eapol_sm_set_use_eapol_start, as setting
require_handshake implies this and achieves the same result when starting
the SM.
Since FT operates over Authenticate/Associate, it makes the most sense
for it to behave like the other auth-protos.
This change moves all the FT specific processing out of netdev and into
ft.c. The bulk of the changes were strait copy-pastes from netdev into
ft.c with minor API changes (e.g. remove struct netdev).
The 'in_ft' boolean unforunately is still required for a few reasons:
- netdev_disconnect_event relies on this flag so it can ignore the
disconnect which comes in when doing a fast transition. We cannot
simply check netdev->ap because this would cause the other auth-protos
to not handle a disconnect correctly.
- netdev_associate_event needs to correctly setup the eapol_sm when
in FT mode by setting require_handshake and use_eapol_start to false.
This cannot be handled inside eapol by checking the AKM because an AP
may only advertise a FT AKM, and the initial mobility association
does require the 4-way handshake.
Now the 'ft' module, previously ftutil, will be used to drive FT via
the auth-proto virtual class. This renaming is in preparation as
ftutil will become obsolete since all the IE building/processing is
going to be moved out of netdev. The new ft.c module will utilize
the existing ftutil functionality, but since this is now a full blown
auth protocol naming it 'ft' is better suited.
The duplicate/similar code in netdev_associate_event and
netdev_connect_event leads to very hard to follow code, especially
when you throw OWE/SAE/FILS or full mac cards into the mix.
Currently these protocols finish the connection inside
netdev_associate_event, and set ignore_connect_event. But for full
mac cards we must finish the connection in netdev_connect_event.
In attempt to simplify this, all connections will be completed
and/or the 4-way started in netdev_connect_event. This satisfies
both soft/full mac cards as well as simplifies the FT processing
in netdev_associate_event. Since the FT IEs can be processed in
netdev_connect_event (as they already are to support full mac)
we can assume that any FT processing inside netdev_associate_event
is for a fast transition, not initial mobility association. This
simplifies netdev_ft_process_associate by removing all the blocks
that would get hit if transition == false.
Handling FT this way also fixes FT-SAE which was broken after the
auth-proto changes since the initial mobility association was
never processed if there was an auth-proto running.
SAE was a bit trickier than OWE/FILS because the initial implementation
for SAE did not include parsing raw authenticate frames (netdev skipped
the header and passed just the authentication data). OWE/FILS did not
do this and parse the entire frame in the RX callbacks. Because of this
it was not as simple as just setting some RX callbacks. In addition,
the TX functions include some of the authentication header/data, but
not all (thanks NL80211), so this will require an overhaul to test-sae
since the unit test passes frames from one SM to another to test the
protocol end-to-end (essentially the header needs to be prepended to
any data coming from the TX functions for the end-to-end tests).
Since ERP is only used for FILS and not behaving in the 'normal' ERP
fashion (dealing with actual EAP data, timeouts etc.) we can structure
ERP as a more synchronous protocol, removing the need for a complete
callback.
Now, erp_rx_packet returns a status, so FILS can decide how to handle
any failures. The complete callback was also removed in favor of a
getter for the RMSK (erp_get_rmsk). This allows FILS to syncronously
handle ERP, and potentially fail directly in fils_rx_authenticate.
A new eapol API was added specifically for FILS (eapol_set_started). Since
either way is special cased for FILS, its a bit cleaner to just check the
AKM inside eapol_start and, if FILS, dont start any timeouts or start the
handshake (effectively what eapol_set_started was doing).
This is a new concept applying to any protocol working over authenticate
and/or associate frames (OWE/SAE/FILS). All these protocols behave
similarly enough that they can be unified into a handshake driver
structure.
Now, each protocol will initialize this auth_proto structure inside
their own internal data. The auth_proto will be returned from
the initializer which netdev can then use to manage the protocol by
forwarding authenticate/associate frames into the individual drivers.
The auth_proto consists only of function pointers:
start - starts the protocol
free - frees the driver data
rx_authenticate - receive authenticate frame
rx_associate - receive associate frame
auth_timeout - authenticate frame timed out
assoc_timeout - associate frame timed out
If the setting is true we'll not attempt to remove or create
interfaces on any wiphys and will only use the default interface
(if it exists). If false, force us managing the interfaces. Both
values override the auto logic.
An unexpected Associate event would cause iwd to crash when accessing
netdev->handshake->mde. netdev->handshake is only set if we're
attempting to connect or connected somewhere so check netdev->connected
first.
FILS needs to allocate an extra 16 bytes of key data for the AES-SIV
vector. Instead of leaving it up to the caller to figure this out (as
was done with the GTK builder) eapol_create_common can allocate the
extra space since it knows the MIC length.
This also updates _create_gtk_2_of_2 as it no longer needs to create
an extra data array.
Since FILS does not use a MIC, the 1/4 handler would always get called
for FILS PTK rekeys. We can use the fact that message 1/4 has no MIC as
well as no encrypted data to determine which packet it is. Both no MIC
and no encrypted data means its message 1/4. Anything else is 3/4.
For FILS rekeys, we still derive the PTK using the 4-way handshake.
And for FILS-SHA384 we need the SHA384 KDF variant when deriving.
This change adds both FILS-SHA256 and FILS-SHA384 to the checks
for determining the SHA variant.
crypto_derive_pairwise_ptk was taking a boolean to decide whether to
use SHA1 or SHA256, but for FILS SHA384 may also be required for
rekeys depending on the AKM.
crypto_derive_pairwise_ptk was changed to take l_checksum_type instead
of a boolean to allow for all 3 SHA types.
AP still relies on the get_data/set_length semantics. Its more convenient
to still use these since it avoids the need for extra temporary buffers
when building the rates IE.
The TLV builder APIs were not very intuative, and in some (or all)
cases required access to the builder structure directly, either to
set the TLV buffer or to get the buffer at the end.
This change adds a new API, ie_tlv_builder_set_data, which both sets
the length for the current TLV and copies the TLV data in one go.
This will avoid the need for memcpy(ie_tlv_builder_get_data(...),...)
ie_tlv_builder_finalize was also changed to return a pointer to the
start of the build buffer. This will eliminate the need to access
builder.tlv after building the TLVs.
ie_tlv_builder_init was changed to take an optional buffer to hold
the TLV data. Passing NULL/0 will build the TLV in the internal
buffer. Passing in a pointer and length will build into the passed
in buffer.
Let manager.c signal to wiphy.c when the wiphy parsing from the genl
messages is complete. When we query for existing wiphy using the
GET_WIPHY dump command we get many genl messages per wiphy, on a
notification we only get one message. So after wiphy_create there may
be one or many calls to wiphy_update_from_genl. wiphy_create_complete
is called after all of them, so wiphy.c can be sure it's done with
parsing the wiphy attributes when in prints the new wiphy summary log
message, like it did before manager.c was added.
I had wrongly assumed that all the important wiphy attributes were in
the first message in the dump, but NL80211_ATTR_EXT_FEATURES was not and
wasn't being parsed which was breaking at least testRSSIAgent.
SAE was behaving inconsitently with respect to freeing the state.
It was freeing the SM internally on failure, but requiring netdev
free it on success.
This removes the call to sae_sm_free in sae.c upon failure, and
instead netdev frees the SM in the complete callback in all cases
regardless of success or failure.
From netdev's prospective FILS works the same as OWE/SAE where we create
a fils_sm and forward all auth/assoc frames into the FILS module. The
only real difference is we do not start EAPoL once FILS completes.
FILS (Fast Initial Link Setup) allows a station to negotiate a PTK during
authentication and association. This allows for a faster connection as
opposed to doing full EAP and the 4-way. FILS uses ERP (EAP Reauth Protocol)
to achieve this, but encapsulates the ERP data into an IE inside
authenticate frames. Association is then used to verify both sides have
valid keys, as well as delivering the GTK/IGTK.
FILS will work similar to SAE/OWE/FT where netdev registers a fils_sm, and
then forwards all Auth/Assoc frame data to and from the FILS module.
Keeping the ERP cache on the handshake object allows station.c to
handle all the ERP details and encapsulate them into a handshake.
FILS can then use the ERP cache right from the handshake rather
than getting it itself.
wiphy_select_akm needed to be updated to take a flag, which can be
set to true if there are known reauth keys for this connection. If
we have reauth keys, and FILS is available we will choose it.
If the AP send an associate with an unsupported group status, OWE
was completely starting over and sending out an authenticate frame
when it could instead just resend the associate frame with a
different group.
With FILS support coming there needs to be a way to set the PTK directly.
Other AKMs derive the PTK via the 4-way handshake, but FILS computes the
PTK on its own.
This reverts commit 1e337259ce.
Using util_get_username was wrong in this context. MSCHAPv2 expects us
to only strip the domain name from identities of the form
domain\identity. util_get_username would also strip identities of the
form username@domain.com.
FILS-SHA384 got overlooked and the kek length was being hard coded
to 32 bytes when encrypting the key data. There was also one occurence
where the kek_len was just being set incorrectly.
If the input length is 16 bytes, this means aes_siv_decrypt should
only be verifying the 16 byte SIV and not decrypting any data. If
this is the case, we can skip over the whole AES-CTR portion of
AES-SIV and only verify the SIV.
In eapol_key_handle, 'have_snonce' is checked before decrypting the
key data. For FILS, there will be no snonce so this check can be
skipped if mic_len == 0.
The GTK handshake for FILS uses AES-SIV to encrypt the key data, and
does away with the MIC completely. Now, when finalizing the 2/2 GTK
packet we check the MIC length, and if zero we assume FILS is being
used and we use AES-SIV to encrypt the key data.
For FILS, there is no actual data being encrypted for GTK 2/2 (hence
why the input data length is zero). This results in only the SIV
being generated, which essentially serves the same purpose as a MIC.
FILS does not use a MIC, as well as requires encrypted data on GTK 2/2.
This updates eapol_create_gtk_2_of_2 to pass in extra data to
eapol_create_common, which will reserve room for this encrypted data.
Extra data is only reserved if mic_len == 0.
FILS does not use a MIC in EAPoL frames and also requires encrypted
data on all EAPoL frames. In the common builder the mic_len is now
checked and the flags are set appropriately.
FILS authentication does away with the MIC, so checking for key_mic
in the eapol key frame does not allow FILS to work. Now we pass in
the mic_len to eapol_verify_gtk_1_of_2, and if it is non-zero we can
check that the MIC is present in the frame.
FILS does not require an eapol_sm for authentication, but rekeys
are still performed using the 4-way handshake. Because of this
FILS needs to create a eapol_sm in a 'started' state, but without
calling eapol_start as this will initialize EAP and create handshake
timeouts.
This allows EAPoL to wait for any 4-way packets, and handle them
as rekeys.
ERP (EAP Reauthentication Protocol) allows a station to quickly
reauthenticate using keys from a previous EAP authentication.
This change both implements ERP as well as moves the key cache into
the ERP module.
ERP in its current form is here to only support FILS. ERP is likely not
widespread and there is no easy way to determine if an AP supports ERP
without trying it. Attempting ERP with a non-ERP enabled AP will actually
result in longer connection times since ERP must fail and then full EAP
is done afterwards. For this reason ERP was separated from EAP and a
separate ERP state machine must be created. As it stands now, ERP cannot
be used on its own, only with FILS.
Quick scan uses a set of frequencies associated with the
known networks. This allows to reduce the scan latency.
At this time, the frequency selection follows a very simple
logic by taking all known frequencies from the top 5 most
recently connected networks.
If connection isn't established after the quick scan attempt,
we fall back to the full periodic scan.
Instead of handling NEW_WIPHY events and WIHPY_DUMP events in a similar
fashion, split up the paths to optimize iwd startup time. There's
fundamentally no reason to wait a second (and eat up file-descriptor
resources for timers unnecessarily) when we can simply start an
interface dump right after the wiphy dump.
In case a new wiphy is added in the middle of a wiphy dump, we will
likely get a new wiphy event anyway, in which case a setup_timeout will
be created and we will ignore this phy during the interface dump
processing.
This also optimizes the case of iwd being re-started, in which case
there are no interfaces present.
Separate out the two types of NEW_WIPHY handlers into separate paths and
factor out the common code into a utility function.
Dumps of CMD_NEW_WIPHY can be split up over several messages, while
CMD_NEW_WIPHY events (generated when a new card is plugged in) are
stuffed into a single message.
This also prepares ground for follow-on commits where we will handle the
two types of events differently.
src/netdev.c:netdev_create_from_genl() Skipping duplicate netdev wlp2s0[3]
Aborting (signal 11) [/home/denkenz/iwd/src/iwd]
++++++++ backtrace ++++++++
#0 0x7fc4c7a4e930 in /lib64/libc.so.6
#1 0x40ea13 in netdev_getlink_cb() at src/netdev.c:4654
#2 0x468cab in process_message() at ell/netlink.c:183
#3 0x4690a3 in can_read_data() at ell/netlink.c:289
#4 0x46681d in io_callback() at ell/io.c:126
#5 0x4651cd in l_main_iterate() at ell/main.c:473
#6 0x46530e in l_main_run() at ell/main.c:516
#7 0x465626 in l_main_run_with_signal() at ell/main.c:642
#8 0x403df8 in main() at src/main.c:513
#9 0x7fc4c7a39bde in /lib64/libc.so.6
Mirror netdev.c white/blacklist logic. If either or both the whitelist
and the blacklist are given also fall back to not touching the existing
interface setup on the wiphy.
If we get an error during DEL_INTERFACE or NEW_INTERFACE we may be
dealing with a driver that doesn't implement virtual interfaces or
doesn't implement deleting the default interface. In this case fall
back to using the first usable interface that we've detected on this
wiphy.
There's at least one full-mac driver that doesn't implement the cfg80211
.del_virtual_intf and .add_virtual_intf methods and at least one that
only allows P2P interfaces to be manipulated. mac80211 drivers seem to
at least implement those methods but I didn't check to see if there are
driver where they'd eventually return EOPNOTSUPP.
This is probably the trickiest part in this patchset. I'm introducing a
new logic where instead of using the interfaces that we find present
when a wiphy is detected, which would normally be the one default
interface per wiphy but could be 0 or more than one, we create one
ourselves with the socket owner attribute and use exactly one for
Station, AP and Ad-Hoc modes. When IWD starts we delete all the
interfaces on existing wiphys that we're going to use (as determined by
the wiphy white/blacklists) or freshly hotplugged ones, and only then we
register the interface we're going to use meaning that the wiphy's
limits on the number of concurrent interfaces of each type should be at
0. Otherwise we'd be unlikely to be abe to create the station interface
as most adapters only allow one. After that we ignore any interfaces
that may be created by other processes as we have no use for multiple
station interfaces.
At this point manager.c only keeps local state for wiphys during
the interface setup although when we start adding P2P code we will be
creating and removing interfaces multiple times during the wiphy's
runtime and may need to track it here or in wiphy.c. We do not
specifically check the interface number limits received during the wiphy
dump, if we need to create any interfaces and we're over the driver's
maximum for that specific iftype we'll still attempt it and report error
if it fails.
I tested this and it seems to work with my laptop's intel card and some
USB hotplug adapters.
The latest refactoring ended up assuming that FT related elements would
be handled in netdev_associate_event. However, FullMac cards (that do
not generate netdev_associate_event) could still connect using FT AKMs
and perform the Initial mobility association. In such cases the FTE
element was required but ended up not being set into the handshake.
This caused the handshake to fail during PTK 1_of_4 processing.
Fix this by making sure that FTE + related info is set into the
handshake, albeit with a lower sanity checking level since the
elements have been processed by the firmware already.
Note that it is currently impossible for actual FTs to be performed on
FullMac cards, so the extra logic and sanity checking to handle these
can be skipped.
Add functionality to read and parse the known frequencies
from permanent storage on start of the service. On service
shutdown, we sync the known frequencies back to the permanent
storage.
Each known network (previously connected) will have a set
of known frequencies associated with it, e.g. a set of
frequencies from all BSSs observed. The list of known
frequencies is sorted with the most recently observed
frequency in the head.
Previously, the scan results were disregarded once the new
ones were available. To enable the scan scenarios where the
new scan results are delivered in parts, we introduce a
concept of aging BSSs and will remove them based on
retention time.
Add manager.c, a new file where the wiphy and interface creation/removal
will be handled and interface use policies will be implemented. Since
not all kernel-side nl80211 interfaces are tied to kernel-side netdevs,
netdev.c can't manage all of the interfaces that we will be using, so
the logic is being moved to a common place where all interfaces on a
wiphy will be managed according to the policy, device support for things
like P2P and user enabling/disabling/connecting with P2P which require
interfaces to be dynamically added and removed.
Add wiphy_create, wiphy_update_from_genl and wiphy_destroy that together
will let a new file command the wiphy creation, updates and deletion
with the same functionality the current config notification handler
implements in wiphy.c.
As mentioned in code comments the name is NUL-terminated so there's no
need to return the length path, which was ignored in some occasions
anyway. Consistently treat it as NUL-terminated but also validate.
Make netdev_create_from_genl public and change signature to return the
created netdev or NULL. Also add netdev_destroy that destroys and
unregisters the created netdevs. Both will be used to move the
whole interface management to a new file.
The handshake_state only holds a single AKM value. FILS depends on the AP
supporting EAP as well as FILS. The first time IWD connects, it will do a
full EAP auth. Subsequent connections (assuming FILS is supported) will use
FILS. But if the AP does not support FILS there is no reason to cache the
ERP keys.
This adds the supp_fils to the handshake_state. Now, station.c can set this
flag while building the handshake. This flag can later be checked when
caching the ERP keys.
This allows IWD to cache ERP keys after a full EAP run. Caching
allows IWD to quickly connect to the network later on using ERP or
FILS.
The cache will contain the EAP Identity, Session ID, EMSK, SSID and
optionally the ERP domain. For the time being, the cache entry
lifetimes are hard coded to 24 hours. Eventually the cache should
be written to disk to allow ERP/FILS to work after a reboot or
IWD restart.
mschaputil already had similar functionality, but ERP will need this
as well. These two functions will also handle identities with either
'@' or '\' to separate the user and domain.
Many operations performed during an error in load_settings were the same
as the ones performed when freeing the eap object. Add eap_free_common
to unify these.
EAP identites are recommended to follow RFC 4282 (The Network Access
Identifier). This RFC recommends a maximum NAI length of 253 octets.
It also mentions that RADIUS is only able to support NAIs of 253
octets.
Because of this, IWD should not allow EAP identities larger than 253
bytes. This change adds a check in eap_load_settings to verify the
identity does not exceed this limit.
The associate event is only important for OWE and FT. If neither of
these conditions (or FT initial association) are happening we do
not need to continue further processing the associate event.
802.11 mandates that IEs inside management frames are presented in a
given order. However, in the real world, many APs seem to ignore the
rules and send their IEs in seemingly arbitrary order, especially when
it comes to VENDOR tags. Change this function to no longer be strict in
enforcing the order.
Also, drop checking of rules specific to Probe Responses. These will
have to be handled separately (most likely by the AP module) since
802.11-2016, Section 11.1.4.3.5 essentially allows just about anything.
In netdev_associate_event the ignore_connect_event was getting set true,
but afterwards there were still potential failure paths. Now, once in
assoc_failed we explicitly set ignore_connect_event to false so the
the failure can be handled properly inside netdev_connect_event
The list of PSK/8021x AKM's in security_determine was getting long,
and difficult to keep under 80 characters. This moves them all into
two new macros, AKM_IS_PSK/AKM_IS_8021X.
It was assumed that the hunt-and-peck loop was guarenteed to find
a PWE. This was incorrect in terms of kernel support. If a system
does not have support for AF_ALG or runs out of file descriptors
the KDFs may fail. The loop continued to run if found == false,
which is also incorrect because we want to stop after 20 iterations
regarless of success.
This changes the loop to a for loop so it will always exit after
the set number of iterations.
CC src/scan.o
src/scan.c: In function ‘scan_bss_compute_rank’:
src/scan.c:1048:4: warning: this decimal constant is unsigned only in ISO C90
factor = factor * data_rate / 2340000000 +
The auto-connect state will now consist of the two phases:
STATION_STATE_AUTOCONNECT_QUICK and STATION_STATE_AUTOCONNECT_FULL.
The auto-connect will always start with STATION_STATE_AUTOCONNECT_QUICK
and then transition into STATION_STATE_AUTOCONNECT_FULL if no
connection has been established. During STATION_STATE_AUTOCONNECT_QUICK
phase we take advantage of the wireless scans with the limited number
of channels on which the known networks have been observed before.
This approach allows to shorten the time required for the network
sweeps, therefore decreases the connection latency if the connection
is possible. Thereafter, if no connection has been established after
the first phase we transition into STATION_STATE_AUTOCONNECT_FULL and
do the periodic scan just like we did before the split in
STATION_STATE_AUTOCONNECT state.
For simplicity 160Mhz and 80+80Mhz were grouped together when
parsing the VHT capabilities, but the 80+80 bits were left in
vht_widht_map. This could cause an overflow when getting the
width map.
wiphy_select_akm will now check if BIP is supported, and if MFPR is
set in the scan_bss before returning either SAE AKMs. This will allow
fallback to another PSK AKM (e.g. hybrid APs) if any of the requirements
are not met.
Replace existing uses of memset to clear secrets with explicit_bzero to
make sure it doesn't get optimized away. This has some side effects as
documented in gcc docs but is still recommended.
In eap_secret_info_free make sure we clear both strings in the case of
EAP_SECRET_REMOTE_USER_PASSWORD secrets.
Environments with several AP's, all at low signal strength may
want to lower the roaming RSSI threshold to prevent IWD from
roaming excessively. This adds an option 'roam_rssi_threshold',
which is still defaulted to -70.
Also printing keys with l_debug conditional on an environment variable
as someone wanting debug logs, or leaving debug on accidentally, does
not necessarily want the keys in the logs and in memory.
At some point the connect command builder was modified, and the
control port over NL80211 check was moved to inside if (is_rsn).
For WPS, no supplicant_ie was set, so CONTROL_PORT_OVER_NL80211
was never set into CMD_CONNECT. This caused IWD to expect WPS
frames over netlink, but the kernel was sending them over the
legacy route.
This commit hardens the iwd.service.in template file for systemd
services. The following is a short explanation for each added directive:
+PrivateTmp=true
If true, sets up a new file system namespace for the executed processes
and mounts private /tmp and /var/tmp directories inside it that is not
shared by processes outside of the namespace.
+NoNewPrivileges=true
If true, ensures that the service process and all its children can never
gain new privileges through execve() (e.g. via setuid or setgid bits, or
filesystem capabilities).
+PrivateDevices=true
If true, sets up a new /dev mount for the executed processes and only
adds API pseudo devices such as /dev/null, /dev/zero or /dev/random (as
well as the pseudo TTY subsystem) to it, but no physical devices such as
/dev/sda, system memory /dev/mem, system ports /dev/port and others.
+ProtectHome=yes
If true, the directories /home, /root and /run/user are made
inaccessible and empty for processes invoked by this unit.
+ProtectSystem=strict
If set to "strict" the entire file system hierarchy is mounted
read-only, except for the API file system subtrees /dev, /proc and /sys
(protect these directories using PrivateDevices=,
ProtectKernelTunables=, ProtectControlGroups=).
+ReadWritePaths=/var/lib/iwd/
Sets up a new file system namespace for executed processes. These
options may be used to limit access a process might have to the file
system hierarchy. Each setting takes a space-separated list of paths
relative to the host's root directory (i.e. the system running the
service manager). Note that if paths contain symlinks, they are resolved
relative to the root directory set with RootDirectory=/RootImage=.
Paths listed in ReadWritePaths= are accessible from within
the namespace with the same access modes as from outside of
it.
+ProtectControlGroups=yes
If true, the Linux Control Groups (cgroups(7)) hierarchies accessible
through /sys/fs/cgroup will be made read-only to all processes of the
unit.
+ProtectKernelModules=yes
If true, explicit module loading will be denied. This allows module
load and unload operations to be turned off on modular kernels.
For further explanation to all directives see `man systemd.directives`
Hostapd has now been updated to include the group number when rejecting
the connection with UNSUPP_FINITE_CYCLIC_GROUP. We still need the existing
len == 0 check because old hostapd versions will still behave this way.
The single-use password is apparently sent in plaintext over the network
but at least try to prevent it from staying in the memory until we know
it's been used.
station.c generates the IEs we will need to use for the
Authenticate/Associate and EAPoL frames and sets them into the
handshake_state object. However the driver may modify some of them
during CMD_CONNECT and we need to use those update values so the AP
isn't confused about differing IEs in diffent frames from us.
Specifically the "wl" driver seems to do this at least for the RSN IE.
The KDF function processes data in 32 byte chunks so for groups which
primes are not divisible by 32 bytes, you will get a buffer overflow
when copying the last chunk of data.
Now l_checksum_get_digest is limited to the bytes remaining in the
buffer, or 32, whichever is the smallest.
Since eapol_encrypt_key_data already calculates the key data length and
encodes it into the key frame, we can just return this length and avoid
having to obtain it again from the frame.
Similar to SAE, EAP-PWD derives an ECC point (PWE). It is possible
for information to be gathered from the timing of this derivation,
which could be used to to recover the password.
This change adapts EAP-PWD to use the same mitigation technique as
SAE where we continue to derive ECC points even after we have found
a valid point. This derivation loop continues for a set number of
iterations (20 in this case), so anyone timing it will always see
the same timings for every run of the protocol.
This is not used by any of the scan notify callback implementations and
for P2P we're going to need to scan on an interface without an ifindex
so without this the other changes should be mostly contained in scan.
Also add a mask parameter to wiphy_get_supported_iftypes to make sure
the SupportedModes property only contains the values that can be used
as Device.Mode.
dbus_iftype_to_string returns NULL for unknown iftypes, the strdup will
also return NULL and ret[i] will be assigned a NULL. As a result
the l_strjoinv will not print the known iftypes that might have come
after that and will the l_strfreev will leak the strduped strings.
sc->state would get set when the TRIGGERED event arrived or when the
triggered callback for our own SCAN_TRIGGER command is received.
However it would not get reset to NOT_RUNNING when the NEW_SCAN_RESULTS
event is received, instead we'd first request the results with GET_SCAN
and only reset sc->state when that returns. If during that command a
new scan gets triggered, the GET_SCAN callback would still reset
sc->state and clobber the value set by the new scan.
To fix that repurpose sc->state to only track that period from the
TRIGGERED signal to the NEW_SCAN_RESULTS signal. sc->triggered can be
used to check if we're still waiting for the GET_SCAN command and
sc->start_cmd_id to check if we're waiting for the scan to get
triggered, so one of these three variables will now always indicate if
a scan is in progress.
We can crash if we abort the connection, but the connect command has
already gone through. In this case we will get a sequence of
authenticate_event, associate_event, connect_event. The first and last
events don't crash since they check whether netdev->connected is true.
However, this causes an annoying warning to be printed.
Fix this by introducing an 'aborting' flag and ignore all connection
related events if it is set.
++++++++ backtrace ++++++++
Now that the OWE failure/retry is handled in netdev, we can catch
all associate error status' inside owe_rx_associate rather than only
catching UNSUPP_FINITE_CYCLIC_GROUP.
Apart from OWE, the association event was disregarded and all association
processing was done in netdev_connect_event. This led to
netdev_connect_event having to handle all the logic of both success and
failure, as well as parsing the association for FT and OWE. Also, without
checking the status code in the associate frame there is the potential
for the kernel to think we are connected even if association failed
(e.g. rogue AP).
This change introduces two flags into netdev, expect_connect_failure and
ignore_connect_event. All the FT processing that was once in
netdev_connect_event has now been moved into netdev_associate_event, as
well as non-FT associate frame processing. The connect event now only
handles failure cases for soft/half MAC cards.
Note: Since fullmac cards rely on the connect event, the eapol_start
and netdev_connect_ok were left in netdev_connect_event. Since neither
auth/assoc events come in on fullmac we shouldn't have any conflict with
the new flags.
Once a connection has completed association, EAPoL is started from
netdev_associate_event (if required) and the ignore_connect_event flag can
be set. This will bypass the connect event.
If a connection has failed during association for whatever reason, we can
set expect_connect_failure, the netdev reason, and the MPDU status code.
This allows netdev_connect_event to both handle the error, and, if required,
send a deauth telling the kernel that we have failed (protecting against the
rogue AP situation).
OWE processing can be completely taken care of inside
netdev_authenticate_event and netdev_associate_event. This removes
the need for OWE specific checks inside netdev_connect_event. We can
now return early out of the connect event if OWE is in progress.
Several Auth/Assoc failure status codes indicate that the connection
failed for reasons such as bandwidth issues, poor channel conditions
etc. These conditions should not result in the BSS being blacklisted
since its likely only a temporary issue and the AP is not actually
"broken" per-se.
This adds support in station.c to temporarily blacklist these BSS's
on a per-network basis. After the connection has completed we clear
out these blacklist entries.
Certain error conditions require that a BSS be blacklisted only for
the duration of the current connection. The existing blacklist
does not allow for this, and since this blacklist is shared between
all interfaces it doesnt make sense to use it for this purpose.
Instead, each network object can contain its own blacklist of
scan_bss elements. New elements can be added with network_blacklist_add.
The blacklist is cleared when the connection completes, either
successfully or not.
Now inside network_bss_select both the per-network blacklist as well as
the global blacklist will be checked before returning a BSS.
Several netdev events benefit from including event data in the callback.
This is similar to how the connect callback works as well. The content
of the event data is documented in netdev.h (netdev_event_func_t).
By including event data for the two disconnect events, we can pass the
reason code to better handle the failure in station.c. Now, inside
station_disconnect_event, we still check if there is a pending connection,
and if so we can call the connect callback directly with HANDSHAKE_FAILED.
Doing it this way unifies the code path into a single switch statment to
handle all failures.
In addition, we pass the RSSI level index as event data to
RSSI_LEVEL_NOTIFY. This removes the need for a getter to be exposed in
netdev.h.
On successful send, scan_send_start(..) used to set msg to NULL,
therefore the further management of the command by the caller was
impossible. This patch removes wrapper around l_genl_family_send()
and lets the callers to take responsibility for the command.
This change cleans up the mess of status vs reason codes. The two
types of codes have already been separated into different enumerations,
but netdev was still treating them the same (with last_status_code).
A new 'event_data' argument was added to the connect callback, which
has a different meaning depending on the result of the connection
(described inside netdev.h, netdev_connect_cb_t). This allows for the
removal of netdev_get_last_status_code since the status or reason
code is now passed via event_data.
Inside the netdev object last_status_code was renamed to last_code, for
the purpose of storing either status or reason. This is only used when
a disconnect needs to be emitted before failing the connection. In all
other cases we just pass the code directly into the connect_cb and do
not store it.
All ocurrences of netdev_connect_failed were updated to use the proper
code depending on the netdev result. Most of these simply changed from
REASON_CODE_UNSPECIFIED to STATUS_CODE_UNSPECIFIED. This was simply for
consistency (both codes have the same value).
netdev_[authenticate|associate]_event's were updated to parse the
status code and, if present, use that if their was a failure rather
than defaulting to UNSPECIFIED.
Even though .check_settings in our EAP method implementations does the
settings validation, .load_settings also has minimum sanity checks to
rule out segfaults if the settings have changed since the last
.check_settings call.
If OWE fails in association there is no reason to send a disconnect
since its already known that we failed. Instead we can directly
call netdev_connect_failed
Instead of sending a reason_code to netdev_setting_keys_failed, make it
take an errno (negative) instead. Since key setting failures are
entirely a system / software issue, and not a protocol issue, it makes
no sense to use a protocol error code.
Some users may need their own control over 2.4/5GHz preference. This
adds a new user option, 'rank_5g_factor', which allows users to increase
or decrease their 5G preference.
This adds support for parsing the VHT IE, which allows a BSS supporting
VHT (80211ac) to be ranked higher than a BSS supporting only HT/basic
rates. Now, with basic/HT/VHT parsing we can calculate the theoretical
maximum data rate for all three and rank the BSS based on that.
This adds HT IE parsing and data rate calculation for HT (80211n)
rates. Now, a BSS supporting HT rates will be ranked higher than
a basic rate BSS, assuming the RSSI is at an acceptable level.
The spec dictates RSSI thresholds for different modulation schemes, which
correlate to different data rates. Until now were were ranking a BSS with
only looking at its advertised data rate, which may not even be possible
if the RSSI does not meet the threshold.
Now, RSSI is taken into consideration and the data rate returned from
parsing (Ext) Supported Rates IE(s) will reflect that.
All over the place we do "ie[1] + 2" for getting the IE length. It
is much clearer to use a macro to do this. The macro also checks
for NULL, and returns zero in this case.
Supported rates will soon be parsed along with HT/VHT capabilities
to determine the best data rate. This will remove the need for the
supported_rates uintset element in scan_bss, as well as the single
API to only parse the supported rates IE. AP still does rely on
this though (since it only supports basic rates), so the parsing
function was moved into ap.c.
In the methods' check_settings do a more complete early check for
possible certificate / private key misconfiguration, including check
that the certificate and the private key are always present or absent
together and that they actually match each other. Do this by encrypting
and decrypting a small buffer because we have no better API for that.
A method's .check_settings method checks for inconsistent setting files
and prints readable errors so there's no need to do that again in
.load_settings, although at some point after removing the duplicate
error messages from the load_settings methods we agreed to keep minimum
checks that could cause a crash e.g. in a corner case like when the
setting file got modified between the check_settings and the
load_settings call. Some error messages have been re-added to
load_settings after that (e.g. in
bb4e1ebd4f) but they're incomplete and not
useful so remove them.
Previously, the storage dir has only been created after a successful
network connection, causing removal of Known Network interface from
Dbus and failure to register dir watcher until daemon is restarted.