[PATCHv3 1/4] Use EtherType: 88 B7 (OUI Extended EtherType) for FT inter-ap communication
Michael Braun
michael-dev at fami-braun.de
Fri Oct 21 04:11:49 PDT 2016
This breaks backward compatiblity.
Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
hostapd/Makefile | 6 ++
hostapd/main.c | 3 +
src/ap/eth_p_oui.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/eth_p_oui.h | 61 ++++++++++++++++
src/ap/hostapd.h | 10 +++
src/ap/wpa_auth.h | 26 +++----
src/ap/wpa_auth_ft.c | 73 ++++++++++++-------
src/ap/wpa_auth_glue.c | 154 ++++++++++++++++++++++++++++++++++++++--
src/utils/common.h | 3 +
9 files changed, 474 insertions(+), 47 deletions(-)
create mode 100644 src/ap/eth_p_oui.c
create mode 100644 src/ap/eth_p_oui.h
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 044c8c0..a667bfb 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -295,6 +295,12 @@ OBJS += ../src/ap/wpa_auth_ft.o
NEED_SHA256=y
NEED_AES_OMAC1=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
ifdef CONFIG_SAE
diff --git a/hostapd/main.c b/hostapd/main.c
index 2c8dbd3..968fe36 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -659,6 +659,9 @@ int main(int argc, char *argv[])
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
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 (;;) {
c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
diff --git a/src/ap/eth_p_oui.c b/src/ap/eth_p_oui.c
new file mode 100644
index 0000000..26e786b
--- /dev/null
+++ b/src/ap/eth_p_oui.c
@@ -0,0 +1,185 @@
+/*
+ * hostapd / IEEE 802 OUI Extended Ethertype
+ * Copyright (c) 2016, Jouni Malinen <j at 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 "hostapd.h"
+#include "eth_p_oui.h"
+#include "l2_packet/l2_packet.h"
+
+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 ouisuffix; /* last byte of oui */
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 ouisuffix,
+ 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->ouisuffix, 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) + 6)
+ /* too short packet */
+ return;
+
+ ethhdr = (struct l2_ethhdr *) buf;
+ /* trim eth_hdr from buf and len */
+ buf += sizeof(*ethhdr);
+ len -= sizeof(*ethhdr);
+
+ dl_list_for_each(receiver, &iface->receiver,
+ struct eth_p_oui_ctx, list) {
+ /* compare all but last byte of oui */
+ if (os_memcmp(buf, global_oui, 5) != 0)
+ continue;
+ /* compare last byte of oui */
+ if (buf[5] != receiver->ouisuffix)
+ continue;
+
+ /* do not pass oui to rx_callback */
+ eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
+ buf + 6, len - 6);
+ }
+}
+
+
+struct eth_p_oui_ctx *
+eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 ouisuffix,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 ouisuffix,
+ 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->ouisuffix = ouisuffix;
+ 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 (strncmp(iface->ifname, ifname,
+ sizeof(iface->ifname)) != 0)
+ continue;
+ found = 1;
+ break;
+ }
+
+ if (!found) {
+ iface = os_zalloc(sizeof(*iface));
+ if (!iface)
+ goto err;
+
+ strncpy(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) + 6 + 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, 5);
+ p[5] = ctx->ouisuffix;
+ p += 6;
+
+ os_memcpy(p, buf, len);
+
+ ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
+ os_free(packet);
+ return ret;
+}
+
+
diff --git a/src/ap/eth_p_oui.h b/src/ap/eth_p_oui.h
new file mode 100644
index 0000000..9a56d15
--- /dev/null
+++ b/src/ap/eth_p_oui.h
@@ -0,0 +1,61 @@
+/*
+ * hostapd / IEEE 802 OUI Extended Ethertype
+ * Copyright (c) 2016, Jouni Malinen <j at 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;
+
+#ifdef CONFIG_ETH_P_OUI
+
+/* 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 ouisuffix,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 ouisuffix,
+ 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);
+
+#else /* CONFIG_ETH_P_OUI */
+
+static inline struct eth_p_oui_ctx *
+eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 ouisuffix,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *dst_addr, u8 ouisuffix,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx)
+{
+ return NULL;
+}
+
+static inline void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
+{
+}
+
+static inline 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)
+{
+ return -1;
+}
+
+static inline 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 /* CONFIG_ETH_P_OUI */
+
+#endif /* ETH_P_OUI_H */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dec46f6..7b18f66 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -53,6 +53,9 @@ struct hapd_interfaces {
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
+#ifdef CONFIG_ETH_P_OUI
+ struct dl_list eth_p_oui;
+#endif /* CONFIG_ETH_P_OUI */
int eloop_initialized;
};
@@ -184,6 +187,13 @@ struct hostapd_data {
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct l2_packet_data *l2;
+
+#ifdef CONFIG_IEEE80211R
+ struct eth_p_oui_ctx *oui_ft_pull;
+ struct eth_p_oui_ctx *oui_ft_push;
+ struct eth_p_oui_ctx *oui_ft_resp;
+#endif /* CONFIG_IEEE80211R */
+
struct wps_context *wps;
int beacon_set_done;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 5712884..b56a69b 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -38,9 +38,9 @@ struct ft_rrb_frame {
#define FT_PACKET_REQUEST 0
#define FT_PACKET_RESPONSE 1
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
-#define FT_PACKET_R0KH_R1KH_PULL 200
-#define FT_PACKET_R0KH_R1KH_RESP 201
-#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_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
@@ -49,11 +49,6 @@ struct ft_rrb_frame {
#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
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 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 r1kh_id[FT_R1KH_ID_LEN];
@@ -67,11 +62,6 @@ struct ft_r0kh_r1kh_pull_frame {
WPA_PMK_NAME_LEN + 2)
#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
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 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
@@ -87,11 +77,6 @@ struct ft_r0kh_r1kh_resp_frame {
WPA_PMK_NAME_LEN + 2)
#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
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 */
u8 timestamp[4]; /* current time in seconds since unix epoch, little
* endian */
@@ -221,6 +206,8 @@ struct wpa_auth_callbacks {
void *ctx), void *cb_ctx);
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
size_t data_len);
+ int (*send_oui)(void *ctx, const u8 *dst, u8 ouisuffix, const u8 *data,
+ size_t data_len);
#ifdef CONFIG_IEEE80211R
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
@@ -327,6 +314,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_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
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 ouisuffix, const u8 *data,
+ size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index b3a7de9..fc96675 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -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 ouisuffix, const u8 *data, size_t data_len)
+{
+ if (wpa_auth->cb.send_oui == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %d send to " MACSTR,
+ ouisuffix, MAC2STR(dst));
+ return wpa_auth->cb.send_oui(wpa_auth->cb.ctx, dst, ouisuffix, data,
+ data_len);
+}
+
+
static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
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));
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
* buffer for the data. */
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)
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;
}
@@ -1461,11 +1470,6 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
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
* buffer for the data. */
os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
@@ -1495,7 +1499,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
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;
}
@@ -1736,13 +1741,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
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);
if (alen < 1 + 1 + 2 * ETH_ALEN) {
@@ -1820,6 +1818,35 @@ 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 ouisuffix, const u8 *data,
+ size_t data_len)
+{
+ wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
+ MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - ouisuffix=%d", ouisuffix);
+
+ if (is_multicast_ether_addr(dst_addr)) {
+ wpa_printf(MSG_ERROR, "FT: RRB-OUI received frame from remote "
+ "AP " MACSTR " to multicast address " MACSTR,
+ MAC2STR(src_addr), MAC2STR(dst_addr));
+ return;
+ }
+
+ switch (ouisuffix) {
+ 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 void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
struct wpa_ft_pmk_r0_sa *pmk_r0,
struct ft_remote_r1kh *r1kh,
@@ -1831,11 +1858,6 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
u8 *crypt;
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
* buffer for the data. */
os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
@@ -1860,7 +1882,8 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
plain, crypt) < 0)
return;
- 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));
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 2a5a940..3f6d2f4 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -17,6 +17,7 @@
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "l2_packet/l2_packet.h"
+#include "eth_p_oui.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "preauth_auth.h"
@@ -467,7 +468,8 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211R
- if (proto == ETH_P_RRB && hapd->iface->interfaces &&
+ if (proto == ETH_P_RRB &&
+ hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
int res;
struct wpa_auth_ft_iface_iter_data idata;
@@ -487,6 +489,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
return hapd->driver->send_ether(hapd->drv_priv, dst,
hapd->own_addr, proto,
data, data_len);
+
if (hapd->l2 == NULL)
return -1;
@@ -504,6 +507,103 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
+struct wpa_auth_oui_iface_iter_data {
+ struct hostapd_data *src_hapd;
+ const u8 *dst;
+ const u8 *data;
+ size_t data_len;
+ u8 ouisuffix;
+};
+
+
+static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
+{
+ struct wpa_auth_oui_iface_iter_data *idata = ctx;
+ struct hostapd_data *hapd;
+ struct eth_p_oui_ctx *oui_ctx;
+ 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) &&
+ os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0)
+ continue;
+
+ switch (idata->ouisuffix) {
+ case FT_PACKET_R0KH_R1KH_PULL:
+ oui_ctx = hapd->oui_ft_pull;
+ break;
+ case FT_PACKET_R0KH_R1KH_PUSH:
+ oui_ctx = hapd->oui_ft_push;
+ break;
+ case FT_PACKET_R0KH_R1KH_RESP:
+ oui_ctx = hapd->oui_ft_resp;
+ break;
+ default:
+ oui_ctx = NULL;
+ break;
+ }
+
+ if (oui_ctx == NULL)
+ continue;
+
+ eth_p_oui_deliver(oui_ctx, idata->src_hapd->own_addr,
+ idata->dst, idata->data, idata->data_len);
+ }
+
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 ouisuffix,
+ const u8 *data, size_t data_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct eth_p_oui_ctx *oui_ctx;
+
+#ifdef CONFIG_IEEE80211R
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface) {
+ int res;
+ struct wpa_auth_oui_iface_iter_data idata;
+
+ idata.src_hapd = hapd;
+ idata.dst = dst;
+ idata.data = data;
+ idata.data_len = data_len;
+ idata.ouisuffix = ouisuffix;
+ 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 */
+
+ switch (ouisuffix) {
+ case FT_PACKET_R0KH_R1KH_PULL:
+ oui_ctx = hapd->oui_ft_pull;
+ break;
+ case FT_PACKET_R0KH_R1KH_PUSH:
+ oui_ctx = hapd->oui_ft_push;
+ break;
+ case FT_PACKET_R0KH_R1KH_RESP:
+ oui_ctx = hapd->oui_ft_resp;
+ break;
+ default:
+ oui_ctx = NULL;
+ break;
+ }
+
+ if (oui_ctx == NULL)
+ return -1;
+
+ return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len);
+}
+
+
#ifdef CONFIG_IEEE80211R
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
@@ -582,6 +682,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 ouisuffix, 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, ouisuffix, buf,
+ len);
+}
+
+
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
@@ -598,6 +714,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
struct wpa_auth_callbacks cb;
const u8 *wpa_ie;
size_t wpa_ie_len;
+#ifdef CONFIG_IEEE80211R
+ const char *ft_iface;
+#endif /* CONFIG_IEEE80211R */
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
@@ -620,6 +739,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
cb.send_ether = hostapd_wpa_auth_send_ether;
+ cb.send_oui = hostapd_wpa_auth_send_oui;
#ifdef CONFIG_IEEE80211R
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
cb.add_sta = hostapd_wpa_auth_add_sta;
@@ -653,9 +773,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
- hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
- 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);
if (hapd->l2 == NULL &&
(hapd->driver == NULL ||
@@ -664,6 +784,26 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
"interface");
return -1;
}
+
+ hapd->oui_ft_pull = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_PULL,
+ hostapd_rrb_oui_receive,
+ hapd);
+ hapd->oui_ft_push = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_PUSH,
+ hostapd_rrb_oui_receive,
+ hapd);
+ hapd->oui_ft_resp = eth_p_oui_register(hapd, ft_iface,
+ FT_PACKET_R0KH_R1KH_RESP,
+ hostapd_rrb_oui_receive,
+ hapd);
+ if (hapd->oui_ft_pull == NULL ||
+ hapd->oui_ft_push == NULL ||
+ hapd->oui_ft_resp == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open "
+ "ETH_P_OUI interface");
+ return -1;
+ }
}
#endif /* CONFIG_IEEE80211R */
@@ -706,5 +846,11 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
l2_packet_deinit(hapd->l2);
hapd->l2 = NULL;
+ eth_p_oui_unregister(hapd->oui_ft_pull);
+ hapd->oui_ft_pull = NULL;
+ eth_p_oui_unregister(hapd->oui_ft_resp);
+ hapd->oui_ft_resp = NULL;
+ eth_p_oui_unregister(hapd->oui_ft_push);
+ hapd->oui_ft_push = NULL;
#endif /* CONFIG_IEEE80211R */
}
diff --git a/src/utils/common.h b/src/utils/common.h
index 7785677..b85c0fa 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -331,6 +331,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val)
#ifndef ETH_P_RRB
#define ETH_P_RRB 0x890D
#endif /* ETH_P_RRB */
+#ifndef ETH_P_OUI
+#define ETH_P_OUI 0x88B7
+#endif /* ETH_P_OUI */
#ifdef __GNUC__
--
2.1.4
More information about the Hostap
mailing list