From 3345c56fbba8935fa71393e00d8f38291a2553af Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 1 Mar 2023 09:30:24 -0600 Subject: [PATCH] ft: Introduce ft_authenticate_onchannel Currently when we try FT-over-Air, the Authenticate frame is always sent via offchannel infrastructure We request the driver to go offchannel, then send the Authenticate frame. This works fine as long as the target AP is on a different channel. On some networks some (or all) APs might actually be located on the same channel. In this case going offchannel will result in some drivers not actually sending the Authenticate frame until after the offchannel operation completes. Work around this by introducing a new ft_authenticate variant that will not request an offchannel operation first. --- src/ft.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/ft.h | 1 + 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/ft.c b/src/ft.c index f173099d..8ae683a7 100644 --- a/src/ft.c +++ b/src/ft.c @@ -40,6 +40,8 @@ #include "src/offchannel.h" #include "src/wiphy.h" +static const unsigned int FT_ONCHANNEL_TIME = 300u; /* ms */ + static ft_tx_frame_func_t tx_frame = NULL; static ft_tx_associate_func_t tx_assoc = NULL; static struct l_queue *info_list = NULL; @@ -63,6 +65,7 @@ struct ft_info { struct ie_ft_info ft_info; bool parsed : 1; + bool onchannel : 1; }; /* @@ -1009,8 +1012,17 @@ void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame, info->parsed = true; cancel: - /* Verified to be expected target, offchannel can be canceled */ - offchannel_cancel(netdev_get_wdev_id(netdev), info->offchannel_id); + /* + * Verified to be expected target, offchannel or onchannel work can + * now be canceled + */ + if (info->onchannel) { + l_timeout_remove(info->timeout); + info->timeout = NULL; + wiphy_radio_work_done(netdev_get_wiphy(netdev), info->work.id); + } else + offchannel_cancel(netdev_get_wdev_id(netdev), + info->offchannel_id); } static void ft_send_authenticate(void *user_data) @@ -1023,6 +1035,8 @@ static void ft_send_authenticate(void *user_data) struct iovec iov[2]; struct mmpdu_authentication auth; + l_debug(""); + /* Authentication body */ auth.algorithm = L_CPU_TO_LE16(MMPDU_AUTH_ALGO_FT); auth.transaction_sequence = L_CPU_TO_LE16(1); @@ -1079,6 +1093,45 @@ int ft_authenticate(uint32_t ifindex, const struct scan_bss *target) return 0; } +static void ft_onchannel_timeout(struct l_timeout *timeout, void *user_data) +{ + struct ft_info *info = user_data; + struct netdev *netdev = netdev_find(info->ifindex); + + wiphy_radio_work_done(netdev_get_wiphy(netdev), info->work.id); +} + +static bool ft_send_authenticate_onchannel(struct wiphy_radio_work_item *work) +{ + struct ft_info *info = l_container_of(work, struct ft_info, work); + + ft_send_authenticate(info); + + info->timeout = l_timeout_create_ms(FT_ONCHANNEL_TIME, + ft_onchannel_timeout, + info, NULL); + return false; +} + +struct wiphy_radio_work_item_ops ft_onchannel_ops = { + .do_work = ft_send_authenticate_onchannel, +}; + +int ft_authenticate_onchannel(uint32_t ifindex, const struct scan_bss *target) +{ + struct netdev *netdev = netdev_find(ifindex); + struct handshake_state *hs = netdev_get_handshake(netdev); + struct ft_info *info = ft_info_new(hs, target); + + info->onchannel = true; + + wiphy_radio_work_insert(netdev_get_wiphy(netdev), &info->work, + WIPHY_WORK_PRIORITY_FT, &ft_onchannel_ops); + l_queue_push_tail(info_list, info); + + return 0; +} + int ft_associate(uint32_t ifindex, const uint8_t *addr) { struct netdev *netdev = netdev_find(ifindex); diff --git a/src/ft.h b/src/ft.h index f3f19599..51bbe3bc 100644 --- a/src/ft.h +++ b/src/ft.h @@ -43,3 +43,4 @@ void ft_clear_authentications(uint32_t ifindex); int ft_action(uint32_t ifindex, uint32_t freq, const struct scan_bss *target); int ft_associate(uint32_t ifindex, const uint8_t *addr); int ft_authenticate(uint32_t ifindex, const struct scan_bss *target); +int ft_authenticate_onchannel(uint32_t ifindex, const struct scan_bss *target);