mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 00:38:24 -05:00
FT: Replace inter-AP protocol with use of OUI Extended Ethertype
Replace the previously used extension of IEEE 802.11 managed Ethertype 89-0d (originally added for Remote Request/Response in IEEE 802.11r) with Ethertype 88-b7 (OUI Extended EtherType) for FT inter-AP communication. The new design uses a more properly assigned identifier for the messages. This assigns the OUI 00:13:74 vendor-specific subtype 0x0001 for the new hostapd AP-to-AP communication purposes. Subtypes 1 (PULL), 2 (RESP), and 3 (PUSH) are also assigned in this commit for the R0KH-R1KH protocol. This breaks backward compatibility, i.e., hostapd needs to be updated on all APs at the same time to allow FT to remain functional. Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
This commit is contained in:
parent
0ed5e9467f
commit
50bd8e0a90
@ -252,6 +252,12 @@ OBJS += src/ap/wpa_auth_ft.c
|
|||||||
NEED_SHA256=y
|
NEED_SHA256=y
|
||||||
NEED_AES_OMAC1=y
|
NEED_AES_OMAC1=y
|
||||||
NEED_AES_UNWRAP=y
|
NEED_AES_UNWRAP=y
|
||||||
|
NEED_ETH_P_OUI=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_ETH_P_OUI
|
||||||
|
L_CFLAGS += -DCONFIG_ETH_P_OUI
|
||||||
|
OBJS += src/ap/eth_p_oui.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef CONFIG_SAE
|
ifdef CONFIG_SAE
|
||||||
|
@ -295,6 +295,12 @@ OBJS += ../src/ap/wpa_auth_ft.o
|
|||||||
NEED_SHA256=y
|
NEED_SHA256=y
|
||||||
NEED_AES_OMAC1=y
|
NEED_AES_OMAC1=y
|
||||||
NEED_AES_UNWRAP=y
|
NEED_AES_UNWRAP=y
|
||||||
|
NEED_ETH_P_OUI=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_ETH_P_OUI
|
||||||
|
CFLAGS += -DCONFIG_ETH_P_OUI
|
||||||
|
OBJS += ../src/ap/eth_p_oui.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef CONFIG_SAE
|
ifdef CONFIG_SAE
|
||||||
|
@ -666,6 +666,9 @@ int main(int argc, char *argv[])
|
|||||||
interfaces.global_iface_name = NULL;
|
interfaces.global_iface_name = NULL;
|
||||||
interfaces.global_ctrl_sock = -1;
|
interfaces.global_ctrl_sock = -1;
|
||||||
dl_list_init(&interfaces.global_ctrl_dst);
|
dl_list_init(&interfaces.global_ctrl_dst);
|
||||||
|
#ifdef CONFIG_ETH_P_OUI
|
||||||
|
dl_list_init(&interfaces.eth_p_oui);
|
||||||
|
#endif /* CONFIG_ETH_P_OUI */
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
|
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
|
||||||
|
191
src/ap/eth_p_oui.c
Normal file
191
src/ap/eth_p_oui.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* hostapd / IEEE 802 OUI Extended EtherType 88-B7
|
||||||
|
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "utils/eloop.h"
|
||||||
|
#include "l2_packet/l2_packet.h"
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "eth_p_oui.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
|
||||||
|
* EtherType 88-B7. This file implements this with OUI 00:13:74 and
|
||||||
|
* vendor-specific subtype 0x0001.
|
||||||
|
*/
|
||||||
|
static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
|
||||||
|
|
||||||
|
struct eth_p_oui_iface {
|
||||||
|
struct dl_list list;
|
||||||
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
struct l2_packet_data *l2;
|
||||||
|
struct dl_list receiver;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_p_oui_ctx {
|
||||||
|
struct dl_list list;
|
||||||
|
struct eth_p_oui_iface *iface;
|
||||||
|
/* all data needed to deliver and unregister */
|
||||||
|
u8 oui_suffix; /* last byte of OUI */
|
||||||
|
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix,
|
||||||
|
const u8 *buf, size_t len);
|
||||||
|
void *rx_callback_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
|
||||||
|
ctx->oui_suffix, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct eth_p_oui_iface *iface = ctx;
|
||||||
|
struct eth_p_oui_ctx *receiver;
|
||||||
|
const struct l2_ethhdr *ethhdr;
|
||||||
|
|
||||||
|
if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
|
||||||
|
/* too short packet */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethhdr = (struct l2_ethhdr *) buf;
|
||||||
|
/* trim eth_hdr from buf and len */
|
||||||
|
buf += sizeof(*ethhdr);
|
||||||
|
len -= sizeof(*ethhdr);
|
||||||
|
|
||||||
|
/* verify OUI and vendor-specific subtype match */
|
||||||
|
if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
|
||||||
|
return;
|
||||||
|
buf += sizeof(global_oui);
|
||||||
|
len -= sizeof(global_oui);
|
||||||
|
|
||||||
|
dl_list_for_each(receiver, &iface->receiver,
|
||||||
|
struct eth_p_oui_ctx, list) {
|
||||||
|
if (buf[0] != receiver->oui_suffix)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
|
||||||
|
buf + 1, len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct eth_p_oui_ctx *
|
||||||
|
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||||
|
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix,
|
||||||
|
const u8 *buf, size_t len),
|
||||||
|
void *rx_callback_ctx)
|
||||||
|
{
|
||||||
|
struct eth_p_oui_iface *iface;
|
||||||
|
struct eth_p_oui_ctx *receiver;
|
||||||
|
int found = 0;
|
||||||
|
struct hapd_interfaces *interfaces;
|
||||||
|
|
||||||
|
receiver = os_zalloc(sizeof(*receiver));
|
||||||
|
if (!receiver)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
receiver->oui_suffix = oui_suffix;
|
||||||
|
receiver->rx_callback = rx_callback;
|
||||||
|
receiver->rx_callback_ctx = rx_callback_ctx;
|
||||||
|
|
||||||
|
interfaces = hapd->iface->interfaces;
|
||||||
|
|
||||||
|
dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
|
||||||
|
list) {
|
||||||
|
if (os_strcmp(iface->ifname, ifname) != 0)
|
||||||
|
continue;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
iface = os_zalloc(sizeof(*iface));
|
||||||
|
if (!iface)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
|
||||||
|
iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
|
||||||
|
iface, 1);
|
||||||
|
if (!iface->l2) {
|
||||||
|
os_free(iface);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
dl_list_init(&iface->receiver);
|
||||||
|
|
||||||
|
dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
dl_list_add_tail(&iface->receiver, &receiver->list);
|
||||||
|
receiver->iface = iface;
|
||||||
|
|
||||||
|
return receiver;
|
||||||
|
err:
|
||||||
|
os_free(receiver);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct eth_p_oui_iface *iface;
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface = ctx->iface;
|
||||||
|
|
||||||
|
dl_list_del(&ctx->list);
|
||||||
|
os_free(ctx);
|
||||||
|
|
||||||
|
if (dl_list_empty(&iface->receiver)) {
|
||||||
|
dl_list_del(&iface->list);
|
||||||
|
l2_packet_deinit(iface->l2);
|
||||||
|
os_free(iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct eth_p_oui_iface *iface = ctx->iface;
|
||||||
|
u8 *packet, *p;
|
||||||
|
size_t packet_len;
|
||||||
|
int ret;
|
||||||
|
struct l2_ethhdr *ethhdr;
|
||||||
|
|
||||||
|
packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
|
||||||
|
packet = os_zalloc(packet_len);
|
||||||
|
if (!packet)
|
||||||
|
return -1;
|
||||||
|
p = packet;
|
||||||
|
|
||||||
|
ethhdr = (struct l2_ethhdr *) packet;
|
||||||
|
os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
|
||||||
|
os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
|
||||||
|
ethhdr->h_proto = host_to_be16(ETH_P_OUI);
|
||||||
|
p += sizeof(*ethhdr);
|
||||||
|
|
||||||
|
os_memcpy(p, global_oui, sizeof(global_oui));
|
||||||
|
p[sizeof(global_oui)] = ctx->oui_suffix;
|
||||||
|
p += sizeof(global_oui) + 1;
|
||||||
|
|
||||||
|
os_memcpy(p, buf, len);
|
||||||
|
|
||||||
|
ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
|
||||||
|
os_free(packet);
|
||||||
|
return ret;
|
||||||
|
}
|
28
src/ap/eth_p_oui.h
Normal file
28
src/ap/eth_p_oui.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* hostapd / IEEE 802 OUI Extended Ethertype
|
||||||
|
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ETH_P_OUI_H
|
||||||
|
#define ETH_P_OUI_H
|
||||||
|
|
||||||
|
struct eth_p_oui_ctx;
|
||||||
|
struct hostapd_data;
|
||||||
|
|
||||||
|
/* rx_callback only gets payload after OUI passed as buf */
|
||||||
|
struct eth_p_oui_ctx *
|
||||||
|
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||||
|
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix,
|
||||||
|
const u8 *buf, size_t len),
|
||||||
|
void *rx_callback_ctx);
|
||||||
|
void eth_p_oui_unregister(struct eth_p_oui_ctx *eth_p_oui);
|
||||||
|
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||||
|
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||||
|
|
||||||
|
#endif /* ETH_P_OUI_H */
|
@ -2019,6 +2019,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
|||||||
hapd->dhcp_sock = -1;
|
hapd->dhcp_sock = -1;
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
dl_list_init(&hapd->l2_queue);
|
dl_list_init(&hapd->l2_queue);
|
||||||
|
dl_list_init(&hapd->l2_oui_queue);
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
return hapd;
|
return hapd;
|
||||||
|
@ -53,6 +53,9 @@ struct hapd_interfaces {
|
|||||||
#ifndef CONFIG_NO_VLAN
|
#ifndef CONFIG_NO_VLAN
|
||||||
struct dynamic_iface *vlan_priv;
|
struct dynamic_iface *vlan_priv;
|
||||||
#endif /* CONFIG_NO_VLAN */
|
#endif /* CONFIG_NO_VLAN */
|
||||||
|
#ifdef CONFIG_ETH_P_OUI
|
||||||
|
struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
|
||||||
|
#endif /* CONFIG_ETH_P_OUI */
|
||||||
int eloop_initialized;
|
int eloop_initialized;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,6 +191,10 @@ struct hostapd_data {
|
|||||||
|
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
struct dl_list l2_queue;
|
struct dl_list l2_queue;
|
||||||
|
struct dl_list l2_oui_queue;
|
||||||
|
struct eth_p_oui_ctx *oui_pull;
|
||||||
|
struct eth_p_oui_ctx *oui_resp;
|
||||||
|
struct eth_p_oui_ctx *oui_push;
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
struct wps_context *wps;
|
struct wps_context *wps;
|
||||||
|
@ -37,10 +37,12 @@ struct ft_rrb_frame {
|
|||||||
|
|
||||||
#define FT_PACKET_REQUEST 0
|
#define FT_PACKET_REQUEST 0
|
||||||
#define FT_PACKET_RESPONSE 1
|
#define FT_PACKET_RESPONSE 1
|
||||||
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
|
|
||||||
#define FT_PACKET_R0KH_R1KH_PULL 200
|
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r. These
|
||||||
#define FT_PACKET_R0KH_R1KH_RESP 201
|
* use OUI Extended EtherType as the encapsulating format. */
|
||||||
#define FT_PACKET_R0KH_R1KH_PUSH 202
|
#define FT_PACKET_R0KH_R1KH_PULL 0x01
|
||||||
|
#define FT_PACKET_R0KH_R1KH_RESP 0x02
|
||||||
|
#define FT_PACKET_R0KH_R1KH_PUSH 0x03
|
||||||
|
|
||||||
#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
|
#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
|
||||||
#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
||||||
@ -49,11 +51,6 @@ struct ft_rrb_frame {
|
|||||||
#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
|
#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
|
||||||
|
|
||||||
struct ft_r0kh_r1kh_pull_frame {
|
struct ft_r0kh_r1kh_pull_frame {
|
||||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
|
||||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
|
|
||||||
le16 data_length; /* little endian length of data (44) */
|
|
||||||
u8 ap_address[ETH_ALEN];
|
|
||||||
|
|
||||||
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
|
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
|
||||||
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
|
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
|
||||||
u8 r1kh_id[FT_R1KH_ID_LEN];
|
u8 r1kh_id[FT_R1KH_ID_LEN];
|
||||||
@ -67,11 +64,6 @@ struct ft_r0kh_r1kh_pull_frame {
|
|||||||
WPA_PMK_NAME_LEN + 2)
|
WPA_PMK_NAME_LEN + 2)
|
||||||
#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
|
#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
|
||||||
struct ft_r0kh_r1kh_resp_frame {
|
struct ft_r0kh_r1kh_resp_frame {
|
||||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
|
||||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
|
|
||||||
le16 data_length; /* little endian length of data (78) */
|
|
||||||
u8 ap_address[ETH_ALEN];
|
|
||||||
|
|
||||||
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
|
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
|
||||||
u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
|
u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
|
||||||
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
|
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
|
||||||
@ -87,11 +79,6 @@ struct ft_r0kh_r1kh_resp_frame {
|
|||||||
WPA_PMK_NAME_LEN + 2)
|
WPA_PMK_NAME_LEN + 2)
|
||||||
#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
|
#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
|
||||||
struct ft_r0kh_r1kh_push_frame {
|
struct ft_r0kh_r1kh_push_frame {
|
||||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
|
||||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
|
|
||||||
le16 data_length; /* little endian length of data (82) */
|
|
||||||
u8 ap_address[ETH_ALEN];
|
|
||||||
|
|
||||||
/* Encrypted with AES key-wrap */
|
/* Encrypted with AES key-wrap */
|
||||||
u8 timestamp[4]; /* current time in seconds since unix epoch, little
|
u8 timestamp[4]; /* current time in seconds since unix epoch, little
|
||||||
* endian */
|
* endian */
|
||||||
@ -226,6 +213,8 @@ struct wpa_auth_callbacks {
|
|||||||
void *ctx), void *cb_ctx);
|
void *ctx), void *cb_ctx);
|
||||||
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
|
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
|
||||||
size_t data_len);
|
size_t data_len);
|
||||||
|
int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
|
||||||
|
size_t data_len);
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||||
int (*send_ft_action)(void *ctx, const u8 *dst,
|
int (*send_ft_action)(void *ctx, const u8 *dst,
|
||||||
@ -345,6 +334,9 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
|||||||
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
|
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
|
||||||
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||||
const u8 *data, size_t data_len);
|
const u8 *data, size_t data_len);
|
||||||
|
void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix, const u8 *data,
|
||||||
|
size_t data_len);
|
||||||
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
|
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
|
@ -41,6 +41,19 @@ static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_ft_rrb_oui_send(struct wpa_authenticator *wpa_auth,
|
||||||
|
const u8 *dst, u8 oui_suffix,
|
||||||
|
const u8 *data, size_t data_len)
|
||||||
|
{
|
||||||
|
if (!wpa_auth->cb->send_oui)
|
||||||
|
return -1;
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR,
|
||||||
|
oui_suffix, MAC2STR(dst));
|
||||||
|
return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
|
||||||
|
data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
|
static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
|
||||||
const u8 *dst, const u8 *data, size_t data_len)
|
const u8 *dst, const u8 *data, size_t data_len)
|
||||||
{
|
{
|
||||||
@ -337,11 +350,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
|
|||||||
"address " MACSTR, MAC2STR(r0kh->addr));
|
"address " MACSTR, MAC2STR(r0kh->addr));
|
||||||
|
|
||||||
os_memset(&frame, 0, sizeof(frame));
|
os_memset(&frame, 0, sizeof(frame));
|
||||||
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
|
|
||||||
frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
|
|
||||||
frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
|
|
||||||
os_memcpy(frame.ap_address, sm->wpa_auth->addr, ETH_ALEN);
|
|
||||||
|
|
||||||
/* aes_wrap() does not support inplace encryption, so use a temporary
|
/* aes_wrap() does not support inplace encryption, so use a temporary
|
||||||
* buffer for the data. */
|
* buffer for the data. */
|
||||||
if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
|
if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
|
||||||
@ -366,7 +374,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
|
|||||||
if (sm->ft_pending_req_ies == NULL)
|
if (sm->ft_pending_req_ies == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
|
wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL,
|
||||||
|
(u8 *) &frame, sizeof(frame));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1470,11 +1479,6 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
|
|||||||
MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
|
MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
|
||||||
|
|
||||||
os_memset(&resp, 0, sizeof(resp));
|
os_memset(&resp, 0, sizeof(resp));
|
||||||
resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
|
|
||||||
resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
|
|
||||||
resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
|
|
||||||
os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
|
|
||||||
|
|
||||||
/* aes_wrap() does not support inplace encryption, so use a temporary
|
/* aes_wrap() does not support inplace encryption, so use a temporary
|
||||||
* buffer for the data. */
|
* buffer for the data. */
|
||||||
os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
|
os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
|
||||||
@ -1507,7 +1511,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
|
|||||||
|
|
||||||
os_memset(pmk_r0, 0, PMK_LEN);
|
os_memset(pmk_r0, 0, PMK_LEN);
|
||||||
|
|
||||||
wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
|
wpa_ft_rrb_oui_send(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP,
|
||||||
|
(u8 *) &resp, sizeof(resp));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1746,13 +1751,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
|
|
||||||
return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
|
|
||||||
if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
|
|
||||||
return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
|
|
||||||
if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
|
|
||||||
return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
|
|
||||||
|
|
||||||
wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
|
wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
|
||||||
|
|
||||||
if (alen < 1 + 1 + 2 * ETH_ALEN) {
|
if (alen < 1 + 1 + 2 * ETH_ALEN) {
|
||||||
@ -1830,6 +1828,43 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix, const u8 *data,
|
||||||
|
size_t data_len)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
|
||||||
|
MACSTR, MAC2STR(src_addr));
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
|
||||||
|
|
||||||
|
if (is_multicast_ether_addr(src_addr)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"FT: RRB-OUI received frame from multicast address "
|
||||||
|
MACSTR, MAC2STR(src_addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_multicast_ether_addr(dst_addr)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"FT: RRB-OUI received frame from remote AP " MACSTR
|
||||||
|
" to multicast address " MACSTR,
|
||||||
|
MAC2STR(src_addr), MAC2STR(dst_addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (oui_suffix) {
|
||||||
|
case FT_PACKET_R0KH_R1KH_PULL:
|
||||||
|
wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
|
||||||
|
break;
|
||||||
|
case FT_PACKET_R0KH_R1KH_RESP:
|
||||||
|
wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
|
||||||
|
break;
|
||||||
|
case FT_PACKET_R0KH_R1KH_PUSH:
|
||||||
|
wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
|
static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_ft_pmk_r0_sa *pmk_r0,
|
struct wpa_ft_pmk_r0_sa *pmk_r0,
|
||||||
struct ft_remote_r1kh *r1kh,
|
struct ft_remote_r1kh *r1kh,
|
||||||
@ -1841,11 +1876,6 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
|
|||||||
u8 *crypt;
|
u8 *crypt;
|
||||||
|
|
||||||
os_memset(&frame, 0, sizeof(frame));
|
os_memset(&frame, 0, sizeof(frame));
|
||||||
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
|
|
||||||
frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
|
|
||||||
frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
|
|
||||||
os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
|
|
||||||
|
|
||||||
/* aes_wrap() does not support inplace encryption, so use a temporary
|
/* aes_wrap() does not support inplace encryption, so use a temporary
|
||||||
* buffer for the data. */
|
* buffer for the data. */
|
||||||
os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
|
os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
|
||||||
@ -1871,7 +1901,8 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
|
|||||||
plain, crypt) < 0)
|
plain, crypt) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
|
wpa_ft_rrb_oui_send(wpa_auth, r1kh->addr, FT_PACKET_R0KH_R1KH_PUSH,
|
||||||
|
(u8 *) &frame, sizeof(frame));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||||
#include "eap_server/eap.h"
|
#include "eap_server/eap.h"
|
||||||
#include "l2_packet/l2_packet.h"
|
#include "l2_packet/l2_packet.h"
|
||||||
|
#include "eth_p_oui.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ieee802_1x.h"
|
#include "ieee802_1x.h"
|
||||||
#include "preauth_auth.h"
|
#include "preauth_auth.h"
|
||||||
@ -565,6 +566,152 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_ETH_P_OUI
|
||||||
|
static struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd,
|
||||||
|
u8 oui_suffix)
|
||||||
|
{
|
||||||
|
switch (oui_suffix) {
|
||||||
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
|
case FT_PACKET_R0KH_R1KH_PULL:
|
||||||
|
return hapd->oui_pull;
|
||||||
|
case FT_PACKET_R0KH_R1KH_RESP:
|
||||||
|
return hapd->oui_resp;
|
||||||
|
case FT_PACKET_R0KH_R1KH_PUSH:
|
||||||
|
return hapd->oui_push;
|
||||||
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ETH_P_OUI */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
|
|
||||||
|
struct oui_deliver_later_data {
|
||||||
|
struct dl_list list;
|
||||||
|
u8 src_addr[ETH_ALEN];
|
||||||
|
u8 dst_addr[ETH_ALEN];
|
||||||
|
size_t data_len;
|
||||||
|
u8 oui_suffix;
|
||||||
|
/* followed by data_len octets of data */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct oui_deliver_later_data *data, *n;
|
||||||
|
struct eth_p_oui_ctx *oui_ctx;
|
||||||
|
|
||||||
|
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
|
||||||
|
struct oui_deliver_later_data, list) {
|
||||||
|
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
|
||||||
|
if (hapd->wpa_auth && oui_ctx) {
|
||||||
|
eth_p_oui_deliver(oui_ctx, data->src_addr,
|
||||||
|
data->dst_addr,
|
||||||
|
(const u8 *) (data + 1),
|
||||||
|
data->data_len);
|
||||||
|
}
|
||||||
|
dl_list_del(&data->list);
|
||||||
|
os_free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wpa_auth_oui_iface_iter_data {
|
||||||
|
struct hostapd_data *src_hapd;
|
||||||
|
const u8 *dst_addr;
|
||||||
|
const u8 *data;
|
||||||
|
size_t data_len;
|
||||||
|
u8 oui_suffix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
|
||||||
|
{
|
||||||
|
struct wpa_auth_oui_iface_iter_data *idata = ctx;
|
||||||
|
struct oui_deliver_later_data *data;
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
for (j = 0; j < iface->num_bss; j++) {
|
||||||
|
hapd = iface->bss[j];
|
||||||
|
if (hapd == idata->src_hapd)
|
||||||
|
continue;
|
||||||
|
if (!is_multicast_ether_addr(idata->dst_addr) &&
|
||||||
|
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* defer eth_p_oui_deliver until next eloop step as this is
|
||||||
|
* when it would be triggerd from reading from sock
|
||||||
|
* This avoids
|
||||||
|
* hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv,
|
||||||
|
* that is calling hapd0:recv handler from within
|
||||||
|
* hapd0:send directly.
|
||||||
|
*/
|
||||||
|
data = os_zalloc(sizeof(*data) + idata->data_len);
|
||||||
|
if (!data)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
|
||||||
|
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
|
||||||
|
os_memcpy(data + 1, idata->data, idata->data_len);
|
||||||
|
data->data_len = idata->data_len;
|
||||||
|
data->oui_suffix = idata->oui_suffix;
|
||||||
|
|
||||||
|
dl_list_add(&hapd->l2_oui_queue, &data->list);
|
||||||
|
|
||||||
|
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
|
||||||
|
hapd, NULL))
|
||||||
|
eloop_register_timeout(0, 0,
|
||||||
|
hostapd_oui_deliver_later,
|
||||||
|
hapd, NULL);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
|
||||||
|
const u8 *data, size_t data_len)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_ETH_P_OUI
|
||||||
|
struct hostapd_data *hapd = ctx;
|
||||||
|
struct eth_p_oui_ctx *oui_ctx;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
|
if (hapd->iface->interfaces &&
|
||||||
|
hapd->iface->interfaces->for_each_interface) {
|
||||||
|
struct wpa_auth_oui_iface_iter_data idata;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
idata.src_hapd = hapd;
|
||||||
|
idata.dst_addr = dst;
|
||||||
|
idata.data = data;
|
||||||
|
idata.data_len = data_len;
|
||||||
|
idata.oui_suffix = oui_suffix;
|
||||||
|
res = hapd->iface->interfaces->for_each_interface(
|
||||||
|
hapd->iface->interfaces, hostapd_wpa_auth_oui_iter,
|
||||||
|
&idata);
|
||||||
|
if (res == 1)
|
||||||
|
return data_len;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
|
oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix);
|
||||||
|
if (!oui_ctx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len);
|
||||||
|
#else /* CONFIG_ETH_P_OUI */
|
||||||
|
return -1;
|
||||||
|
#endif /* CONFIG_ETH_P_OUI */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
|
|
||||||
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
|
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
|
||||||
@ -643,6 +790,22 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr,
|
||||||
|
const u8 *dst_addr, u8 oui_suffix,
|
||||||
|
const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = ctx;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||||
|
MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr));
|
||||||
|
if (!is_multicast_ether_addr(dst_addr) &&
|
||||||
|
os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0)
|
||||||
|
return;
|
||||||
|
wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
||||||
u8 *tspec_ie, size_t tspec_ielen)
|
u8 *tspec_ie, size_t tspec_ielen)
|
||||||
{
|
{
|
||||||
@ -650,6 +813,42 @@ static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
|||||||
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
|
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd,
|
||||||
|
const char *ft_iface)
|
||||||
|
{
|
||||||
|
hapd->oui_pull = eth_p_oui_register(hapd, ft_iface,
|
||||||
|
FT_PACKET_R0KH_R1KH_PULL,
|
||||||
|
hostapd_rrb_oui_receive, hapd);
|
||||||
|
if (!hapd->oui_pull)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hapd->oui_resp = eth_p_oui_register(hapd, ft_iface,
|
||||||
|
FT_PACKET_R0KH_R1KH_RESP,
|
||||||
|
hostapd_rrb_oui_receive, hapd);
|
||||||
|
if (!hapd->oui_resp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hapd->oui_push = eth_p_oui_register(hapd, ft_iface,
|
||||||
|
FT_PACKET_R0KH_R1KH_PUSH,
|
||||||
|
hostapd_rrb_oui_receive, hapd);
|
||||||
|
if (!hapd->oui_push)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
eth_p_oui_unregister(hapd->oui_pull);
|
||||||
|
hapd->oui_pull = NULL;
|
||||||
|
eth_p_oui_unregister(hapd->oui_resp);
|
||||||
|
hapd->oui_resp = NULL;
|
||||||
|
eth_p_oui_unregister(hapd->oui_push);
|
||||||
|
hapd->oui_push = NULL;
|
||||||
|
}
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
|
|
||||||
@ -671,6 +870,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
|||||||
.for_each_sta = hostapd_wpa_auth_for_each_sta,
|
.for_each_sta = hostapd_wpa_auth_for_each_sta,
|
||||||
.for_each_auth = hostapd_wpa_auth_for_each_auth,
|
.for_each_auth = hostapd_wpa_auth_for_each_auth,
|
||||||
.send_ether = hostapd_wpa_auth_send_ether,
|
.send_ether = hostapd_wpa_auth_send_ether,
|
||||||
|
.send_oui = hostapd_wpa_auth_send_oui,
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
.send_ft_action = hostapd_wpa_auth_send_ft_action,
|
.send_ft_action = hostapd_wpa_auth_send_ft_action,
|
||||||
.add_sta = hostapd_wpa_auth_add_sta,
|
.add_sta = hostapd_wpa_auth_add_sta,
|
||||||
@ -713,9 +913,11 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
|||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
if (!hostapd_drv_none(hapd) &&
|
if (!hostapd_drv_none(hapd) &&
|
||||||
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
||||||
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
|
const char *ft_iface;
|
||||||
hapd->conf->bridge :
|
|
||||||
hapd->conf->iface, NULL, ETH_P_RRB,
|
ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge :
|
||||||
|
hapd->conf->iface;
|
||||||
|
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
|
||||||
hostapd_rrb_receive, hapd, 1);
|
hostapd_rrb_receive, hapd, 1);
|
||||||
if (hapd->l2 == NULL &&
|
if (hapd->l2 == NULL &&
|
||||||
(hapd->driver == NULL ||
|
(hapd->driver == NULL ||
|
||||||
@ -724,6 +926,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
|||||||
"interface");
|
"interface");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Failed to open ETH_P_OUI interface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
|
|
||||||
@ -766,7 +974,10 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
|
|||||||
#ifdef CONFIG_IEEE80211R_AP
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX);
|
eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX);
|
||||||
hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */
|
hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */
|
||||||
|
eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX);
|
||||||
|
hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */
|
||||||
l2_packet_deinit(hapd->l2);
|
l2_packet_deinit(hapd->l2);
|
||||||
hapd->l2 = NULL;
|
hapd->l2 = NULL;
|
||||||
|
hostapd_wpa_unregister_ft_oui(hapd);
|
||||||
#endif /* CONFIG_IEEE80211R_AP */
|
#endif /* CONFIG_IEEE80211R_AP */
|
||||||
}
|
}
|
||||||
|
@ -331,6 +331,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
|
|||||||
#ifndef ETH_P_RRB
|
#ifndef ETH_P_RRB
|
||||||
#define ETH_P_RRB 0x890D
|
#define ETH_P_RRB 0x890D
|
||||||
#endif /* ETH_P_RRB */
|
#endif /* ETH_P_RRB */
|
||||||
|
#ifndef ETH_P_OUI
|
||||||
|
#define ETH_P_OUI 0x88B7
|
||||||
|
#endif /* ETH_P_OUI */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
Loading…
Reference in New Issue
Block a user