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.
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).
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)
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
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.
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.
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).
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.
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.
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
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.
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 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.
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
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.
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.
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.
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.
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 ++++++++
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 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.
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.
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