Netdev/AP share several NL80211 commands and each has their own
builder API's. These were moved into a common file nl80211_util.[ch].
A helper was added to AP for building NEW_STATION to make the associate
callback look cleaner (rather than manually building NEW_STATION).
Check that netdev->device is not NULL before doing device_remove()
(which would crash) and emitting NETDEV_WATCH_EVENT_DEL. It may be
NULL if the initial RTM_SETLINK has failed to bring device UP.
In netdev_set_powered also check that no NL80211_CMD_SET_INTERFACE is in
progress because once it returned we would overwrite
netdev->set_powered_cmd_id (could also add a check there but it seems
more logical to just disallow Powered property changes while Mode is
being changed, since we also disallow Mode changes while Powered is
being changed.)
When we detect a new device we either bring it down and then up or only
up. The IFF_UP flag in netdev->ifi_flags is updated before that, then
we send the two rtnl commands and then fire the NETDEV_WATCH_EVENT_NEW
event if either the bring up succeeded or -ERFKILL was returned, so the
device may either be UP or DOWN at that point.
It seems that a RTNL NEWLINK notification is usually received before
the RTNL command callback but I don't think this is guaranteed so update
the IFF_UP flag in the callbacks so that the NETDEV_WATCH_EVENT_NEW
handlers can reliably use netdev_get_is_up()
The NL80211_ATTR_KEY_DEFAULT_TYPES attribute is only parsed by the
kernel if either NL80211_ATTR_KEY_DEFAULT or
NL80211_ATTR_KEY_DEFAULT_MGMT are also present, however these are only
used with NL80211_CMD_SET_KEY and ignored for NEW_KEY. As far as I
understand the default key concept only makes sense for a Tx key because
on Rx all keys can be tried, so we don't need this for client mode. The
kernel decides whether the NEW_KEY is for unicast or multicast based on
whether NL80211_ATTR_KEY_MAC was supplied.
Boiled down, FT over SAE is no different than FT over PSK, apart from
the different AKM suite. The bulk of this change fixes the current
netdev/station logic related to SAE by rebuilding the RSNE and adding
the MDE if present in the handshake to match what the PSK logic does.
A common function was introduced into station which will rebuild the
handshake rsne's for a target network. This is used for both new
network connections as well as fast transitions.
To prepare for FT over SAE, several case/if statements needed to include
IE_RSN_AKM_SUITE_FT_OVER_SAE. Also a new macro was introduced to remove
duplicate if statement code checking for both FT_OVER_SAE and SAE AKM's.
To avoid confusion in case of an authenticator side handshake_state
structure and eapol_sm structure, rename own_ie to supplicant_ie and
ap_ie to authenticator_ie. Also rename
handshake_state_set_{own,ap}_{rsn,wpa} and fix when we call
handshake_state_setup_own_ciphers. As a result
handshake_state_set_authenticator, if needed, should be called before
handshake_state_set_{own,ap}_{rsn,wpa}.
There was somewhat overlapping functionality in the device_watch
infrastructure as well as the netdev_event_watch. This commit combines
the two into a single watch based on the netdev object and cleans up the
various interface additions / removals.
With this commit the interfaces are created when the netdev/device is
switched to Powered=True state AND when the netdev iftype is also in the
correct state for that interface. If the device is brought down, then
all interfaces except the .Device interface are removed.
This will make it easy to implement Device.Mode property properly since
most nl80211 devices need to be brought into Powered=False state prior
to switching the iftype.
The way that netdev_set_linkmode_and_operstate was used resulted in
potential crashes when the netdev was destroyed. This is because netdev
was given as data to l_netlink_send and could be destroyed between the
time of the call and the callback. Since the result of calls to
netdev_set_linkmode_and_operstate is inconsequential, it isn't really
worthwhile tracking these calls in order to cancel them.
This patch simplies the handling of these rtnl calls, makes sure that
netdev isn't passed as user data and rewrites the
netdev_set_linkmode_and_operstate signature to be more consistent with
rtnl_set_powered.
Since all netdevs share the rtnl l_netlink object, it was possible for
netdevs to be destroyed with outstanding commands still executing on the
rtnl object. This can lead to crashes and other nasty situations.
This patch makes sure that Powered requests are always tracked via
set_powered_cmd_id and the request is canceled when netdev is destroyed.
This also implies that netdev_set_powered can now return an -EBUSY error
in case a request is already outstanding.
This removes the authenticator bit in eapol_sm as well as unifies
eapol_register_authenticator and eapol_register. Taking advantage
of the handshake state authenticator bit we no longer have a need
for 2 separate register functions.
ap, and adhoc were also updated to set the authenticator bit in
the handshake and only use eapol_register to register their sm's.
netdev was updated to use the authenticator bit when choosing the
correct key address for adhoc.
In order to plug SAE into the existing connect mechanism the actual
CMD_CONNECT message is never sent, rather sae_register takes care
of sending out CMD_AUTHENTICATE. This required some shuffling of
code in order to handle both eapol and sae. In the case of non-SAE
authentication everything behaves as it did before. When using SAE
an sae_sm is created when a connection is attempted but the eapol_sm
is not. After SAE succeeds it will start association and then create
the eapol_sm and start the 4-way handshake.
This change also adds the handshake SAE events to device and
initializes SAE in main.
Our logic would set CONTROL_PORT_OVER_NL80211 even in cases where
CONTROL_PORT wasn't used (e.g. for open networks). While the kernel
ignored this attribute in this case, it is nicer to set this only if
CONTROL_PORT is intended to be used.
SAE will require some of the same CMD_ASSOCIATE building code that
FT currently uses. This breaks out the common code from FT into
netdev_build_cmd_associate_common.
These will issue a JOIN/LEAVE_IBSS to the kernel. There is
a TODO regarding network configuration. For now, only the
SSID is configurable. This configuration is also required
for AP, but needs to be thought out. Since the current
AP Dbus API has nothing related to configuration items
such as freq/channel or RSN elements they are hard coded,
and will be for Ad-Hoc as well (for now).
Now that the device mode can be changed, netdev must check that
the iftype is correct before starting a connection or disconnecting.
netdev_connect, netdev_connect_wsc, and netdev_disconnect now check
that the iftype is station before continuing.
With the introduction of Ad-Hoc, its not as simple as choosing
aa/spa addresses when setting the keys. Since Ad-Hoc acts as
both the authenticator and supplicant we must check how the netdev
address relates to the particular handshake object as well as
choose the correct key depending on the value of the AA/SPA address.
802.11 states that the higher of the two addresses is to be used
to set the key for the Ad-Hoc connection.
A simple helper was added to choose the correct addressed based on
netdev type and handshake state. netdev_set_tk also checks that
aa > spa in the handshake object when in Ad-Hoc mode. If this is
true then the keys from that handshake are used, otherwise return
and the other handshake key will be used (aa will be > spa).
The station/ap mode behaves exactly the same as before.
For Ad-Hoc networks, the kernel takes care of auth/assoc
and issues a NEW_STATION event when that is complete. This
provides a way to notify when NEW_STATION events occur as
well as forward the MAC of the station to Ad-Hoc.
The two new API's added:
- netdev_station_watch_add()
- netdev_station_watch_remove()
This removes the need for duplicate code in AP/netdev for issuing
a DEL_STATION command. Now AP can issue a DEL_STATION with
netdev_del_station, and specify to either disassociate or deauth
depending on state.
If netdev fails to set the keys, there was no way for device/ap to
know. A new handshake event was added for this. The key setting
failure function was also fixed to support both AP/station iftypes.
It will now automatically send either a disconnect or del_station
depending on the interface type.
In similar manner, netdev_handshake_failed was also modified to
support both AP/station iftypes. Now, any handshake event listeners
should call netdev_handshake_failed upon a handshake failure
event, including AP.
Right now iwd uses Control Port over NL80211 feature if the kernel /
driver supports it. On some kernels this feature is still buggy, so add
an iwd.conf entry to allow the user to override id.
For now the default is to disable this feature until it is more stable.
These checks allow both a station and authenticator to use
the same netdev key install functions. For NEW_KEY and
SET_STATION, the iftype is checked and either handshake->aa
or ->spa is used as the station address for the KEY/STATION
commands. Also, in the failure cases, a disconnect command
is issued only if the iftype is station as this doesn't
apply to AP.
Handshake related netdev events were removed in favor of
handshake events. Now events will be emitted on the handshake
object related to the 4-way handshake and key settings. Events
are:
HANDSHAKE_EVENT_STARTED
HANDSHAKE_EVENT_SETTING_KEYS
HANDSHAKE_EVENT_COMPLETE
HANDSHAKE_EVENT_FAILED
Right now, since netdev only operates in station mode, nothing
listens for COMPLETE/FAILED, as device/wsc gets notified by the
connect_cb when the connection was successful. The COMPLETE/
FAILED were added in preperation for AP moving into eapol/netdev.
When a wifi interface is added/removed to/from a bridge, a
RTM_NEW/DELLINK event is issued. This is the same event used to signal
when an interface is created/deleted.
For this reason the event generated by the bridge code has to be
properly distinguished and handled accordingly. Failing to do so will
result in inconsistencies in iwd which will think an interface has been
deleted when it was actually not.
Detect incoming NEW/DELLINK bridge events and reacts accordingly. For
now, this simply means printing a simple message, as there is no
special logic in iwd for this yet.