netdev: ft: complete FT refactor

This finalizes the refactor by moving all the handshake prep
into FT itself (most was already in there). The netdev-specific
flags and state were added into netdev_ft_tx_associate which
now avoids any need for a netdev API related to FT.

The NETDEV_EVENT_FT_ROAMED event is now emitted once FT completes
(netdev_connect_ok). This did require moving the 'in_ft' flag
setting until after the keys are set into the kernel otherwise
netdev_connect_ok has no context as to if this was FT or some
other connection attempt.

In addition the prev_snonce was removed from netdev. Restoring
the snonce has no value once association begins. If association
fails it will result in a disconnect regardless which requires
a new snonce to be generated
This commit is contained in:
James Prestwood 2022-09-27 12:47:29 -07:00 committed by Denis Kenzior
parent 0e6aaea2a9
commit ad59fb6249
2 changed files with 68 additions and 7 deletions

View File

@ -1123,9 +1123,19 @@ static void ft_info_destroy(void *data)
static void ft_prepare_handshake(struct ft_info *info,
struct handshake_state *hs)
{
handshake_state_set_authenticator_address(hs, info->aa);
memcpy(hs->mde + 2, info->mde, 3);
handshake_state_set_chandef(hs, NULL);
if (!hs->supplicant_ie)
return;
if (info->authenticator_ie)
handshake_state_set_authenticator_ie(hs,
info->authenticator_ie);
memcpy(hs->snonce, info->snonce, sizeof(hs->snonce));
handshake_state_set_fte(hs, info->fte);

View File

@ -1413,6 +1413,15 @@ static void netdev_connect_ok(struct netdev *netdev)
scan_bss_free(netdev->fw_roam_bss);
netdev->fw_roam_bss = NULL;
} else if (netdev->in_ft) {
if (netdev->event_filter)
netdev->event_filter(netdev, NETDEV_EVENT_FT_ROAMED,
NULL, netdev->user_data);
netdev->in_ft = false;
} else if (netdev->connect_cb) {
netdev->connect_cb(netdev, NETDEV_RESULT_OK, NULL,
netdev->user_data);
netdev->connect_cb = NULL;
}
if (netdev->ft_ds_list) {
@ -1420,12 +1429,6 @@ static void netdev_connect_ok(struct netdev *netdev)
netdev->ft_ds_list = NULL;
}
if (netdev->connect_cb) {
netdev->connect_cb(netdev, NETDEV_RESULT_OK, NULL,
netdev->user_data);
netdev->connect_cb = NULL;
}
netdev_rssi_polling_update(netdev);
if (netdev->work.id)
@ -3293,7 +3296,6 @@ static void netdev_associate_event(struct l_genl_msg *msg,
eapol_sm_set_require_handshake(netdev->sm,
false);
netdev->in_ft = false;
netdev->in_reassoc = false;
netdev->associated = true;
return;
@ -4459,6 +4461,7 @@ static int netdev_ft_tx_associate(uint32_t ifindex, uint32_t freq,
struct iovec *ft_iov, size_t n_ft_iov)
{
struct netdev *netdev = netdev_find(ifindex);
struct netdev_handshake_state *nhs;
struct handshake_state *hs = netdev->handshake;
struct l_genl_msg *msg;
struct iovec iov[64];
@ -4467,6 +4470,54 @@ static int netdev_ft_tx_associate(uint32_t ifindex, uint32_t freq,
enum mpdu_management_subtype subtype =
MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_REQUEST;
/*
* At this point there is no going back with FT so reset all the flags
* needed to associate with a new BSS.
*/
netdev->frequency = freq;
netdev->handshake->active_tk_index = 0;
netdev->associated = false;
netdev->operational = false;
netdev->in_ft = true;
/*
* Cancel commands that could be running because of EAPoL activity
* like re-keying, this way the callbacks for those commands don't
* have to check if failures resulted from the transition.
*/
nhs = l_container_of(netdev->handshake,
struct netdev_handshake_state, super);
/* reset key states just as we do in initialization */
nhs->complete = false;
nhs->ptk_installed = false;
nhs->gtk_installed = true;
nhs->igtk_installed = true;
if (nhs->group_new_key_cmd_id) {
l_genl_family_cancel(nl80211, nhs->group_new_key_cmd_id);
nhs->group_new_key_cmd_id = 0;
}
if (nhs->group_management_new_key_cmd_id) {
l_genl_family_cancel(nl80211,
nhs->group_management_new_key_cmd_id);
nhs->group_management_new_key_cmd_id = 0;
}
if (netdev->rekey_offload_cmd_id) {
l_genl_family_cancel(nl80211, netdev->rekey_offload_cmd_id);
netdev->rekey_offload_cmd_id = 0;
}
netdev_rssi_polling_update(netdev);
netdev_cqm_rssi_update(netdev);
if (netdev->sm) {
eapol_sm_free(netdev->sm);
netdev->sm = NULL;
}
msg = netdev_build_cmd_associate_common(netdev);
c_iov = netdev_populate_common_ies(netdev, hs, msg, iov, n_iov, c_iov);