diff --git a/src/ft.c b/src/ft.c index 6897f6d7..40e29341 100644 --- a/src/ft.c +++ b/src/ft.c @@ -40,6 +40,7 @@ struct ft_sm { ft_tx_authenticate_func_t tx_auth; ft_tx_associate_func_t tx_assoc; + ft_get_oci get_oci; void *user_data; }; @@ -640,7 +641,7 @@ static int ft_rx_authenticate(struct auth_proto *ap, const uint8_t *frame, if (ret < 0) goto auth_error; - return ft_tx_reassociate(ft); + return ft->get_oci(ft->user_data); auth_error: return (int)status_code; @@ -783,6 +784,13 @@ static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame, return 0; } +static int ft_rx_oci(struct auth_proto *ap) +{ + struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap); + + return ft_tx_reassociate(ft); +} + static void ft_sm_free(struct auth_proto *ap) { struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap); @@ -890,12 +898,14 @@ static bool ft_start(struct auth_proto *ap) struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs, ft_tx_authenticate_func_t tx_auth, ft_tx_associate_func_t tx_assoc, + ft_get_oci get_oci, void *user_data) { struct ft_sm *ft = l_new(struct ft_sm, 1); ft->tx_auth = tx_auth; ft->tx_assoc = tx_assoc; + ft->get_oci = get_oci; ft->hs = hs; ft->user_data = user_data; @@ -903,6 +913,7 @@ struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs, ft->ap.rx_associate = ft_rx_associate; ft->ap.start = ft_start; ft->ap.free = ft_sm_free; + ft->ap.rx_oci = ft_rx_oci; return &ft->ap; } diff --git a/src/ft.h b/src/ft.h index 6167e0d7..cc25463f 100644 --- a/src/ft.h +++ b/src/ft.h @@ -26,6 +26,7 @@ typedef void (*ft_tx_authenticate_func_t)(struct iovec *iov, size_t iov_len, void *user_data); typedef int (*ft_tx_associate_func_t)(struct iovec *ie_iov, size_t iov_len, void *user_data); +typedef int (*ft_get_oci)(void *user_data); typedef void (*ft_ds_free_func_t)(void *user_data); @@ -60,6 +61,7 @@ bool ft_over_ds_parse_action_ies(struct ft_ds_info *info, struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs, ft_tx_authenticate_func_t tx_auth, ft_tx_associate_func_t tx_assoc, + ft_get_oci get_oci, void *user_data); struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs, diff --git a/src/netdev.c b/src/netdev.c index 9a4eff0f..8610616f 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -2074,6 +2074,21 @@ static void netdev_get_oci_cb(struct l_genl_msg *msg, void *user_data) handshake_state_set_chandef(netdev->handshake, l_steal_ptr(chandef)); done: + if (netdev->ap) { + /* + * Cant do much here. IWD assumes every kernel/driver supports + * this. There is no way of detecting support either. + */ + if (L_WARN_ON(err < 0)) + netdev_connect_failed(netdev, + NETDEV_RESULT_AUTHENTICATION_FAILED, + MMPDU_STATUS_CODE_UNSPECIFIED); + else + auth_proto_rx_oci(netdev->ap); + + return; + } + L_WARN_ON(!eapol_start(netdev->sm)); } @@ -2581,8 +2596,11 @@ process_resp_ies: } if (netdev->sm) { - if (netdev_get_oci(netdev) < 0) - goto deauth; + if (!netdev->handshake->chandef) { + if (netdev_get_oci(netdev) < 0) + goto deauth; + } else if (!eapol_start(netdev->sm)) + goto deauth; return; } @@ -4099,6 +4117,8 @@ static void prepare_ft(struct netdev *netdev, const struct scan_bss *target_bss) netdev->operational = false; netdev->in_ft = true; + handshake_state_set_chandef(netdev->handshake, NULL); + /* * Cancel commands that could be running because of EAPoL activity * like re-keying, this way the callbacks for those commands don't @@ -4273,7 +4293,8 @@ int netdev_fast_transition(struct netdev *netdev, netdev->ap = ft_over_air_sm_new(netdev->handshake, netdev_ft_tx_authenticate, - netdev_ft_tx_associate, netdev); + netdev_ft_tx_associate, + netdev_get_oci, netdev); memcpy(netdev->ap->prev_bssid, orig_bss->addr, ETH_ALEN); wiphy_radio_work_insert(netdev->wiphy, &netdev->work, 1,