@@ -237,6 +237,11 @@ endif
ifdef CONFIG_RSN_PREAUTH
CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
+ifdef CONFIG_RSN_PREAUTH_COPY
+CFLAGS += -DCONFIG_RSN_PREAUTH_COPY
+OBJS += ../src/ap/l2_snoop_pcap.o
+LIBS += -lpcap
+endif
endif
ifdef CONFIG_PEERKEY
@@ -2518,6 +2518,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->rsn_preauth_interfaces = os_strdup(pos);
} else if (os_strcmp(buf, "rsn_preauth_autoconf_bridge") == 0) {
bss->rsn_preauth_autoconf_bridge = atoi(pos);
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ } else if (os_strcmp(buf, "rsn_preauth_copy_iface") == 0) {
+ os_strlcpy(bss->rsn_preauth_copy_iface, pos,
+ sizeof(bss->rsn_preauth_copy_iface));
+#endif /* CONFIG_RSN_PREAUTH_COPY */
#endif /* CONFIG_RSN_PREAUTH */
#ifdef CONFIG_PEERKEY
} else if (os_strcmp(buf, "peerkey") == 0) {
@@ -50,6 +50,9 @@ CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
+# WPA2/IEEE 802.11i RSN pre-authentication full-dynamic packet copy
+CONFIG_RSN_PREAUTH_COPY=y
+
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
@@ -1189,6 +1189,15 @@ own_ip_addr=127.0.0.1
# rsn_preauth_interfaces, they need to be bridges.
# (default: 0 = disabled)
#rsn_preauth_autoconf_bridge=1
+#
+# For pre-authentication with fully dynamic vlans, the packets from the local
+# station need to copied into a different netdev where they can reach the
+# target AP and similar in the opposite direction. This is the netdev where
+# packets from sta to remote ap are send to and packets from remote ap to sta
+# are gathered from.
+# ETH_P_PREAUTH packets can then be filtered from forwarding in the normal data
+# bridge.
+#rsn_preauth_copy_iface=brpreauth
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
# allowed. This is only used with RSN/WPA2.
@@ -120,6 +120,9 @@ struct hostapd_vlan {
char ifname[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ void *rsn_preauth;
+#endif /* CONFIG_RSN_PREAUTH_COPY */
#ifdef CONFIG_FULL_DYNAMIC_VLAN
#define DVLAN_CLEAN_WLAN_PORT 0x8
@@ -319,6 +322,9 @@ struct hostapd_bss_config {
int rsn_preauth;
char *rsn_preauth_interfaces;
int rsn_preauth_autoconf_bridge;
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ char rsn_preauth_copy_iface[IFNAMSIZ+1];
+#endif /* CONFIG_RSN_PREAUTH_COPY */
int peerkey;
#ifdef CONFIG_IEEE80211R
@@ -150,6 +150,12 @@ struct hostapd_data {
struct eapol_authenticator *eapol_auth;
struct rsn_preauth_interface *preauth_iface;
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ /* ctx for snoop preauth packets for STA on BSS preauth_copy_iface */
+ struct rsn_preauth_copy_interface *preauth_copy_iface;
+ /* ctx for snoop preauth packets from STA on BSS conf->iface */
+ struct rsn_preauth_copy_interface *preauth_vlan0;
+#endif
struct os_reltime michael_mic_failure;
int michael_mic_failures;
int tkip_countermeasures;
new file mode 100644
@@ -0,0 +1,72 @@
+/*
+ * hostapd - Layer2 packet snooping interface definition
+ * Copyright (c) 2015, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines an interface for layer 2 (link layer) packet injecting
+ * and snooping.
+ */
+
+#ifndef L2_SNOOP_H
+#define L2_SNOOP_H
+
+/**
+ * struct l2_snoop_data - Internal l2_snoop data structure
+ *
+ * This structure is used by the l2_snoop implementation to store its private
+ * data. Other files use a pointer to this data when calling the l2_snoop
+ * functions, but the contents of this structure should not be used directly
+ * outside l2_snoop implementation.
+ */
+struct l2_snoop_data;
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct l2_snoop_ethhdr {
+ u8 h_dest[ETH_ALEN];
+ u8 h_source[ETH_ALEN];
+ be16 h_proto;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+/**
+ * l2_snoop_init - Initialize l2_snoop interface
+ * @ifname: Interface name
+ * @protocol: Ethernet protocol number in host byte order
+ * @rx_callback: Callback function that will be called for each received packet
+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
+ * Returns: Pointer to internal data or %NULL on failure
+ *
+ * rx_callback function will be called with src_addr pointing to the source
+ * address (MAC address) of the the packet. Buf points to payload including
+ * ethernet header.
+ */
+struct l2_snoop_data * l2_snoop_init(
+ const char *ifname, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx);
+
+/**
+ * l2_snoop_deinit - Deinitialize l2_snoop interface
+ * @l2: Pointer to internal l2_snoop data from l2_snoop_init()
+ */
+void l2_snoop_deinit(struct l2_snoop_data *l2);
+
+/**
+ * l2_snoop_send - Send a packet
+ * @l2: Pointer to internal l2_snoop data from l2_snoop_init()
+ * @buf: Packet contents to be sent; including layer 2 header.
+ * @len: Length of the buffer (including l2 header)
+ * Returns: >=0 on success, <0 on failure
+ */
+int l2_snoop_send(struct l2_snoop_data *l2, const u8 *buf, size_t len);
+
+#endif /* L2_SNOOP_H */
new file mode 100644
@@ -0,0 +1,134 @@
+/*
+ * hostapd - Layer2 packet snooping interface definition
+ * Copyright (c) 2015, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * Implementation based on l2_packet/l2_packet_pcap.c with modifications.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <pcap.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_snoop.h"
+
+
+struct l2_snoop_data {
+ pcap_t *pcap;
+ char ifname[100];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+};
+
+
+int l2_snoop_send(struct l2_snoop_data *l2, const u8 *buf, size_t len)
+{
+ int ret;
+
+ if (l2 == NULL)
+ return -1;
+
+ ret = pcap_sendpacket(l2->pcap, buf, len);
+
+ return ret;
+}
+
+
+static void l2_snoop_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_snoop_data *l2 = eloop_ctx;
+ pcap_t *pcap = sock_ctx;
+ struct pcap_pkthdr hdr;
+ const u_char *packet;
+ struct l2_snoop_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ packet = pcap_next(pcap, &hdr);
+
+ if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_snoop_ethhdr *) packet;
+ buf = (unsigned char *) ethhdr;
+ len = hdr.caplen;
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+
+
+static int l2_snoop_init_libpcap(struct l2_snoop_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 1, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
+ fprintf(stderr, "pcap_setnonblock: %s\n",
+ pcap_geterr(l2->pcap));
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "ether proto 0x%x", protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+
+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+ l2_snoop_receive, l2, l2->pcap);
+
+ return 0;
+}
+
+
+struct l2_snoop_data * l2_snoop_init(
+ const char *ifname, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx)
+{
+ struct l2_snoop_data *l2;
+
+ l2 = os_zalloc(sizeof(struct l2_snoop_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+
+ if (l2_snoop_init_libpcap(l2, protocol)) {
+ os_free(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+void l2_snoop_deinit(struct l2_snoop_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
+ if (l2->pcap)
+ pcap_close(l2->pcap);
+ os_free(l2);
+}
@@ -25,6 +25,9 @@
#include "bridge.h"
#include "dummy.h"
#include "ifconfig.h"
+#ifdef CONFIG_RSN_PREAUTH_COPY
+#include "l2_snoop.h"
+#endif /* CONFIG_RSN_PREAUTH_COPY */
#ifndef ETH_P_PREAUTH
#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
@@ -40,6 +43,23 @@ struct rsn_preauth_interface {
int ifindex;
};
+#ifdef CONFIG_RSN_PREAUTH_COPY
+struct rsn_preauth_copy_interface {
+ struct l2_snoop_data *l2;
+ char ifname[IFNAMSIZ+1];
+ struct hostapd_data *hapd;
+};
+
+
+static struct rsn_preauth_copy_interface*
+rsn_preauth_snoop_init_cb(struct hostapd_data *hapd, char *ifname,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len));
+static void rsn_preauth_snoop_from_sta(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+static void rsn_preauth_snoop_to_sta(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
@@ -153,6 +173,7 @@ fail1:
void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
+ struct hostapd_bss_config *conf = hapd->conf;
struct rsn_preauth_interface *piface, *prev;
#ifdef CONFIG_LIBNL3_ROUTE
char dummy_iface[IFNAMSIZ+1];
@@ -166,7 +187,7 @@ void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
if (hapd->conf->rsn_preauth_autoconf_bridge) {
#ifdef CONFIG_LIBNL3_ROUTE
snprintf(dummy_iface, sizeof(dummy_iface), "pre%s",
- hapd->conf->iface);
+ conf->iface);
ifconfig_down(dummy_iface);
br_delif(prev->ifname, dummy_iface);
dummy_del(dummy_iface);
@@ -176,6 +197,14 @@ void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
os_free(prev->ifname);
os_free(prev);
}
+
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ rsn_preauth_snoop_deinit(hapd, conf->rsn_preauth_copy_iface,
+ hapd->preauth_copy_iface);
+ hapd->preauth_copy_iface = NULL;
+ rsn_preauth_snoop_deinit(hapd, conf->iface, hapd->preauth_vlan0);
+ hapd->preauth_vlan0 = NULL;
+#endif /* CONFIG_RSN_PREAUTH_COPY */
}
@@ -184,7 +213,7 @@ int rsn_preauth_iface_init(struct hostapd_data *hapd)
char *tmp, *start, *end;
if (hapd->conf->rsn_preauth_interfaces == NULL)
- return 0;
+ goto skip_preauth_iface_init;
tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
if (tmp == NULL)
@@ -211,6 +240,20 @@ int rsn_preauth_iface_init(struct hostapd_data *hapd)
break;
}
os_free(tmp);
+
+skip_preauth_iface_init:
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ if (hapd->preauth_copy_iface)
+ rsn_preauth_snoop_deinit(hapd,
+ hapd->conf->rsn_preauth_copy_iface,
+ rsn_preauth_snoop_to_sta);
+
+ hapd->preauth_copy_iface = rsn_preauth_snoop_init_cb(hapd,
+ hapd->conf->rsn_preauth_copy_iface,
+ rsn_preauth_snoop_to_sta);
+ hapd->preauth_vlan0 = rsn_preauth_snoop_init(hapd, hapd->conf->iface);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
return 0;
}
@@ -303,4 +346,199 @@ void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
}
+#ifdef CONFIG_RSN_PREAUTH_COPY
+static struct rsn_preauth_copy_interface*
+rsn_preauth_snoop_init_cb(struct hostapd_data *hapd, char *ifname,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len))
+{
+ struct rsn_preauth_copy_interface *ctx;
+
+ if (!hapd->conf->rsn_preauth_copy_iface[0])
+ return NULL;
+
+ ctx = os_zalloc(sizeof(*ctx));
+
+ if (ctx == NULL) {
+ wpa_printf(MSG_ERROR,
+ "RSN: rsn_preauth_init_cb: Failed to alloc ctx");
+ goto fail;
+ }
+
+ ifconfig_up(ifname);
+
+ os_strlcpy(ctx->ifname, ifname, sizeof(ctx->ifname));
+ ctx->hapd = hapd;
+ ctx->l2 = l2_snoop_init(ifname, ETH_P_PREAUTH, rx_callback, ctx);
+
+ if (ctx->l2 == NULL) {
+ wpa_printf(MSG_ERROR, "RSN: failed to start L2 snooping on %s,"
+ " error: %s", ifname, strerror(errno));
+ goto fail;
+ }
+
+ return ctx;
+fail:
+ if (ctx && ctx->l2)
+ l2_snoop_deinit(ctx->l2);
+ if (ctx)
+ os_free(ctx);
+ return NULL;
+}
+
+void * rsn_preauth_snoop_init(struct hostapd_data *hapd, char *ifname)
+{
+ return rsn_preauth_snoop_init_cb(hapd, ifname,
+ rsn_preauth_snoop_from_sta);
+}
+
+void rsn_preauth_snoop_deinit(struct hostapd_data *hapd, char *ifname,
+ void *ctx_ptr)
+{
+ struct rsn_preauth_copy_interface *ctx = ctx_ptr;
+
+ wpa_printf(MSG_DEBUG, "RSN: deinit pre-authentication snooping"
+ " on %s", ifname);
+
+ if (ctx && ctx->l2)
+ l2_snoop_deinit(ctx->l2);
+ if (ctx)
+ os_free(ctx);
+}
+
+
+struct rsn_preauth_iter_data {
+ struct hostapd_data *src_hapd;
+ const u8 *src_addr;
+ const u8 *dst;
+ const u8 *data;
+ size_t data_len;
+ const char *dest_iface;
+};
+
+
+static int rsn_preauth_iter(struct hostapd_iface *iface, void *ctx)
+{
+ struct rsn_preauth_iter_data *idata = ctx;
+ struct hostapd_data *hapd;
+ unsigned int j;
+ struct rsn_preauth_interface *piface;
+
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ if (hapd == idata->src_hapd)
+ continue;
+ if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0)
+ continue;
+ for (piface = hapd->preauth_iface; piface;
+ piface = piface->next) {
+ if (strcmp(piface->ifname, idata->dest_iface) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "RSN: Send preauth data directly"
+ " to locally managed BSS " MACSTR "@%s -> "
+ MACSTR "@%s via %s",
+ MAC2STR(idata->src_addr),
+ idata->src_hapd->conf->iface,
+ MAC2STR(hapd->own_addr), hapd->conf->iface,
+ idata->dest_iface);
+ rsn_preauth_receive(piface, idata->src_addr,
+ idata->data, idata->data_len);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void rsn_preauth_snoop_from_sta(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct rsn_preauth_copy_interface *l2ctx;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ struct l2_ethhdr *ethhdr;
+ struct rsn_preauth_iter_data idata;
+
+ l2ctx = (struct rsn_preauth_copy_interface *) ctx;
+ hapd = l2ctx->hapd;
+
+ if (!hapd->preauth_copy_iface)
+ return;
+
+ if (len < sizeof(*ethhdr))
+ return;
+ ethhdr = (struct l2_ethhdr *) buf;
+
+ sta = ap_get_sta(hapd, ethhdr->h_source);
+ if (!sta)
+ return;
+
+ wpa_printf(MSG_DEBUG, "RSN: preauth_snoop forward from sta " MACSTR
+ " to ap " MACSTR " on from %s to %s",
+ MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest),
+ l2ctx->ifname, hapd->preauth_copy_iface->ifname);
+
+ idata.src_hapd = hapd;
+ idata.dst = ethhdr->h_dest;
+ idata.data = buf;
+ idata.data_len = len;
+ idata.src_addr = src_addr;
+ idata.dest_iface = hapd->conf->rsn_preauth_copy_iface;
+ if (hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, rsn_preauth_iter,
+ &idata))
+ return;
+ l2_snoop_send(hapd->preauth_copy_iface->l2, buf, len);
+}
+
+static void rsn_preauth_snoop_to_sta(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct rsn_preauth_copy_interface *l2ctx;
+ struct hostapd_data *hapd;
+ struct rsn_preauth_copy_interface *destctx;
+ struct hostapd_vlan *vlan;
+ struct sta_info *sta;
+ struct l2_ethhdr *ethhdr;
+
+ l2ctx = (struct rsn_preauth_copy_interface *) ctx;
+ hapd = l2ctx->hapd;
+
+ if (!hapd->preauth_copy_iface)
+ return;
+
+ if (len < sizeof(*ethhdr))
+ return;
+ ethhdr = (struct l2_ethhdr *) buf;
+
+ sta = ap_get_sta(hapd, ethhdr->h_dest);
+ if (!sta)
+ return;
+
+ destctx = hapd->preauth_vlan0;
+#ifndef CONFIG_NO_VLAN
+ if (sta->vlan_id_bound) {
+ vlan = hapd->conf->vlan;
+ while (vlan) {
+ if (vlan->vlan_id == sta->vlan_id_bound)
+ break;
+ vlan = vlan->next;
+ }
+ if (!vlan)
+ return;
+ destctx = vlan->rsn_preauth;
+ }
+#endif /* CONFIG_NO_VLAN */
+ if (!destctx || !destctx->l2)
+ return;
+
+ wpa_printf(MSG_DEBUG, "RSN: preauth_snoop forward from ap " MACSTR
+ " to sta " MACSTR " if from %s to %s",
+ MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest),
+ l2ctx->ifname, destctx->ifname);
+
+ l2_snoop_send(destctx->l2, buf, len);
+}
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
#endif /* CONFIG_RSN_PREAUTH */
@@ -18,6 +18,12 @@ void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len);
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
+#ifdef CONFIG_RSN_PREAUTH_COPY
+/* snoop packets from STA */
+void * rsn_preauth_snoop_init(struct hostapd_data *hapd, char *ifname);
+void rsn_preauth_snoop_deinit(struct hostapd_data *hapd, char *ifname,
+ void *ctx);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
#else /* CONFIG_RSN_PREAUTH */
@@ -47,6 +53,19 @@ static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
{
}
+#ifdef CONFIG_RSN_PREAUTH_COPY
+static inline void * rsn_preauth_snoop_init(struct hostapd_data *hapd,
+ char *ifname)
+{
+ return NULL;
+}
+
+static inline void rsn_preauth_snoop_deinit(struct hostapd_data *hapd,
+ char *ifname, void *ctx)
+{
+}
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
#endif /* CONFIG_RSN_PREAUTH */
#endif /* PREAUTH_H */
@@ -26,6 +26,11 @@
#include <linux/if_bridge.h>
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#include "wpa_auth_glue.h"
+#ifdef CONFIG_RSN_PREAUTH_COPY
+#include "preauth_auth.h"
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -157,6 +162,12 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ if (!vlan->rsn_preauth)
+ vlan->rsn_preauth = rsn_preauth_snoop_init(hapd,
+ vlan->ifname);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
if (hapd->wpa_auth)
ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
@@ -168,6 +179,10 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ rsn_preauth_snoop_deinit(hapd, vlan->ifname, vlan->rsn_preauth);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
/* group state machine setup failed */
if (hostapd_vlan_if_remove(hapd, vlan->ifname))
wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
@@ -186,6 +201,11 @@ static int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
"WPA deinitialization for VLAN %d failed (%d)",
vlan->vlan_id, ret);
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ rsn_preauth_snoop_deinit(hapd, vlan->ifname, vlan->rsn_preauth);
+ vlan->rsn_preauth = NULL;
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
return hostapd_vlan_if_remove(hapd, vlan->ifname);
}
@@ -450,6 +470,12 @@ static void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
}
ifconfig_up(ifname);
+
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ if (!vlan->rsn_preauth)
+ vlan->rsn_preauth = rsn_preauth_snoop_init(hapd,
+ vlan->ifname);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
}
@@ -523,6 +549,11 @@ static void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
char br_name[IFNAMSIZ];
int i;
+#ifdef CONFIG_RSN_PREAUTH_COPY
+ rsn_preauth_snoop_deinit(hapd, vlan->ifname,
+ vlan->rsn_preauth);
+#endif /* CONFIG_RSN_PREAUTH_COPY */
+
for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
if (tagged[i] == untagged ||
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
@@ -3,6 +3,7 @@
CONFIG_DRIVER_NONE=y
CONFIG_DRIVER_NL80211=y
CONFIG_RSN_PREAUTH=y
+CONFIG_RSN_PREAUTH_COPY=y
#CONFIG_TLS=internal
#CONFIG_INTERNAL_LIBTOMMATH=y