mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-22 13:02:44 +01:00
ft: implement offchannel authentication
A new API was added, ft_authenticate, which will send an authentication frame offchannel via CMD_FRAME. This bypasses the kernel's authentication state allowing multiple auth attempts to take place without disconnecting.
This commit is contained in:
parent
dfdc9fdb3b
commit
391607de93
102
src/ft.c
102
src/ft.c
@ -37,6 +37,8 @@
|
||||
#include "src/util.h"
|
||||
#include "src/netdev.h"
|
||||
#include "src/module.h"
|
||||
#include "src/offchannel.h"
|
||||
#include "src/wiphy.h"
|
||||
|
||||
static ft_tx_frame_func_t tx_frame = NULL;
|
||||
static ft_tx_associate_func_t tx_assoc = NULL;
|
||||
@ -52,6 +54,7 @@ struct ft_info {
|
||||
uint8_t *authenticator_ie;
|
||||
uint8_t prev_bssid[6];
|
||||
uint32_t frequency;
|
||||
uint32_t offchannel_id;
|
||||
|
||||
struct ie_ft_info ft_info;
|
||||
|
||||
@ -1169,6 +1172,101 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame,
|
||||
size_t frame_len)
|
||||
{
|
||||
struct netdev *netdev = netdev_find(ifindex);
|
||||
struct handshake_state *hs = netdev_get_handshake(netdev);
|
||||
struct ft_info *info;
|
||||
uint16_t status;
|
||||
const uint8_t *ies;
|
||||
size_t ies_len;
|
||||
|
||||
info = ft_info_find(ifindex, NULL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (!ft_parse_authentication_resp_frame(frame, frame_len,
|
||||
info->spa, info->aa, info->aa, 2,
|
||||
&status, &ies, &ies_len))
|
||||
return;
|
||||
|
||||
/* Verified to be expected target, offchannel can be canceled */
|
||||
offchannel_cancel(netdev_get_wdev_id(netdev), info->offchannel_id);
|
||||
|
||||
if (status != 0)
|
||||
return;
|
||||
|
||||
if (!ft_parse_ies(info, hs, ies, ies_len))
|
||||
return;
|
||||
|
||||
info->parsed = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void ft_send_authenticate(void *user_data)
|
||||
{
|
||||
struct ft_info *info = user_data;
|
||||
struct netdev *netdev = netdev_find(info->ifindex);
|
||||
struct handshake_state *hs = netdev_get_handshake(netdev);
|
||||
uint8_t ies[256];
|
||||
size_t len;
|
||||
struct iovec iov[2];
|
||||
struct mmpdu_authentication auth;
|
||||
|
||||
/* Authentication body */
|
||||
auth.algorithm = L_CPU_TO_LE16(MMPDU_AUTH_ALGO_FT);
|
||||
auth.transaction_sequence = L_CPU_TO_LE16(1);
|
||||
auth.status = L_CPU_TO_LE16(0);
|
||||
|
||||
iov[0].iov_base = &auth;
|
||||
iov[0].iov_len = sizeof(struct mmpdu_authentication);
|
||||
|
||||
if (!ft_build_authenticate_ies(hs, hs->supplicant_ocvc, info->snonce,
|
||||
ies, &len))
|
||||
return;
|
||||
|
||||
iov[1].iov_base = ies;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
tx_frame(info->ifindex, 0x00b0, info->frequency, info->aa, iov, 2);
|
||||
}
|
||||
|
||||
static void ft_authenticate_destroy(int error, void *user_data)
|
||||
{
|
||||
struct ft_info *info = user_data;
|
||||
|
||||
info->offchannel_id = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no callback here because its assumed that another work item will
|
||||
* be inserted following this call which will check if authentication succeeded
|
||||
* via ft_associate.
|
||||
*
|
||||
* If the netdev goes away while authentication is in-flight station will clear
|
||||
* the authentications during cleanup, and in turn cancel the offchannel
|
||||
* request.
|
||||
*/
|
||||
int ft_authenticate(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->offchannel_id = offchannel_start(netdev_get_wdev_id(netdev),
|
||||
WIPHY_WORK_PRIORITY_FT,
|
||||
target->frequency,
|
||||
200, ft_send_authenticate, info,
|
||||
ft_authenticate_destroy);
|
||||
ft_clear_authentications(ifindex);
|
||||
|
||||
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);
|
||||
@ -1205,6 +1303,10 @@ static bool remove_ifindex(void *data, void *user_data)
|
||||
if (info->ifindex != ifindex)
|
||||
return false;
|
||||
|
||||
if (info->offchannel_id)
|
||||
offchannel_cancel(netdev_get_wdev_id(netdev_find(ifindex)),
|
||||
info->offchannel_id);
|
||||
|
||||
ft_info_destroy(info);
|
||||
return true;
|
||||
}
|
||||
|
3
src/ft.h
3
src/ft.h
@ -85,7 +85,10 @@ void __ft_set_tx_associate_func(ft_tx_associate_func_t func);
|
||||
int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame,
|
||||
size_t frame_len);
|
||||
void __ft_rx_action(uint32_t ifindex, const uint8_t *frame, size_t frame_len);
|
||||
void __ft_rx_authenticate(uint32_t ifindex, const uint8_t *frame,
|
||||
size_t frame_len);
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user