[PATCH v2 19/33] FT: separate RRB interface

Michael Braun michael-dev at fami-braun.de
Sat Sep 24 13:54:00 PDT 2016


Enable using a different interface for RRB messages. In order
to receive messages for the local BSSID (FT_OVER_DS), that
interface needs to have the mac address configured as BSSID.

If hostapd is build with IEEE80211R_MACVLAN, hostapd will add
and use an macvlan interface on top of ft_iface.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 hostapd/Makefile       |  17 +++++++
 hostapd/config_file.c  |   4 ++
 hostapd/defconfig      |   5 ++
 hostapd/hostapd.conf   |  28 +++++++++++
 src/ap/ap_config.h     |   6 +++
 src/ap/macvlan.c       | 130 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/macvlan.h       |  10 ++++
 src/ap/wpa_auth_glue.c |  40 +++++++++++++--
 8 files changed, 237 insertions(+), 3 deletions(-)
 create mode 100644 src/ap/macvlan.c
 create mode 100644 src/ap/macvlan.h

diff --git a/hostapd/Makefile b/hostapd/Makefile
index 20f7ef3..47ba052 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -296,6 +296,10 @@ endif
 ifdef CONFIG_IEEE80211R
 CFLAGS += -DCONFIG_IEEE80211R
 OBJS += ../src/ap/wpa_auth_ft.o
+ifdef CONFIG_IEEE80211R_MACVLAN
+CFLAGS += -DCONFIG_IEEE80211R_MACVLAN
+NEED_MACVLAN=y
+endif
 NEED_SHA256=y
 NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
@@ -851,6 +855,19 @@ endif
 endif
 endif
 
+ifdef NEED_MACVLAN
+ifdef CONFIG_LIBNL32
+ifdef CONFIG_LIBNL3_ROUTE
+OBJS += ../src/ap/macvlan.o
+LIBS += -lnl-3
+LIBS += -lnl-genl-3
+LIBS += -lnl-route-3
+CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
+endif
+endif
+
 ifdef NEED_SHA256
 CFLAGS += -DCONFIG_SHA256
 ifneq ($(CONFIG_TLS), openssl)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e1b5026..0cba230 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1999,6 +1999,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
 	} else if (os_strcmp(buf, "wds_bridge") == 0) {
 		os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
+#ifdef CONFIG_IEEE80211R
+	} else if (os_strcmp(buf, "ft_iface") == 0) {
+		os_strlcpy(bss->ft_iface, pos, sizeof(bss->ft_iface));
+#endif /* CONFIG_IEEE80211R */
 	} else if (os_strcmp(buf, "driver") == 0) {
 		int j;
 		/* clear to get error below if setting is invalid */
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 4659dd1..db35e0b 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -33,6 +33,8 @@ CONFIG_DRIVER_NL80211=y
 # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
 #CONFIG_LIBNL32=y
 
+# Use libnl3-route (used by driver_nl80211.c and required by 80211R_MACVLAN)
+#CONFIG_LIBNL3_ROUTE=y
 
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
@@ -143,6 +145,9 @@ CONFIG_IPV6=y
 # IEEE Std 802.11r-2008 (Fast BSS Transition)
 #CONFIG_IEEE80211R=y
 
+# ft_iface autoconf support
+#CONFIG_IEEE80211R_MACVLAN=y
+
 # Use the hostapd's IEEE 802.11 authentication (ACL), but without
 # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
 #CONFIG_DRIVER_RADIUS_ACL=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index c749501..62bac5a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1304,6 +1304,34 @@ own_ip_addr=127.0.0.1
 # (dot11FTReassociationDeadline)
 #reassociation_deadline=1000
 
+# 802.11r Inter-AP communication
+# When a station roams, it is connected to a current AP and wants to connect to
+# a target AP (R1KH). The station initially connected to an AP (R0KH) before
+# it roams around to the current AP.
+#
+# Now there are two communication patterns you need to be aware of:
+# Over-Air: STA <--> target AP (R1KH) <--> initial AP (R0KH)
+# Over-DS: STA <--> current AP <--> target AP (R1KH) <--> initial AP (R0KH)
+#
+# Communication between the APs is done using a layer-2 protocol, that is to
+# say that addressing is done using MAC addresses.
+# The current AP <--> target AP communication uses the BSSID for addressing and
+# is unencrypted. Thus, both ends need to be listening to their BSSID.
+# The R1KH <--> R0KH communication uses the mac addresses and keys given in the
+# r0kh and r1kh lists below. R1KH looks up the R0KH configuration using R0KH-ID
+# when sending and using MAC address when receiving. Thus both need to be
+# unique. R0KH looks up r1kh configuration using mac address when receiving and
+# replying; it will use R1KH-ID to derive 802.11r data only when pushing to all
+# R1KH in its list.
+# Sending and receiving is done using ft_iface, which defaults to bridge or
+# iface if unset.
+
+# Use a different interface for 802.11r inter-AP communication
+# This interface needs to listen to packets destined for BSSID.
+# If hostapd is build with CONFIG_IEEE80211R_MACVLAN and ft_iface set, hostapd
+# will add an macvlan interace name ft%iface on top of ft_iface given.
+#ft_iface=
+
 # List of R0KHs in the same Mobility Domain
 # format: <MAC address> <NAS Identifier> <128-bit key as hex string>
 # This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 5aeaa0d..2b50c3d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -233,6 +233,12 @@ struct hostapd_bss_config {
 	char bridge[IFNAMSIZ + 1];
 	char vlan_bridge[IFNAMSIZ + 1];
 	char wds_bridge[IFNAMSIZ + 1];
+#ifdef CONFIG_IEEE80211R
+	char ft_iface[IFNAMSIZ + 1];
+#ifdef CONFIG_IEEE80211R_MACVLAN
+	char ft_macvlan[IFNAMSIZ + 1];
+#endif /* CONFIG_IEEE80211R_MACVLAN */
+#endif /* CONFIG_IEEE80211R */
 
 	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
 
diff --git a/src/ap/macvlan.c b/src/ap/macvlan.c
new file mode 100644
index 0000000..683d632
--- /dev/null
+++ b/src/ap/macvlan.c
@@ -0,0 +1,130 @@
+/*
+ * hostapd / WPA authenticator glue code
+ * Copyright (c) 2002-2012, 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"
+
+#ifdef CONFIG_LIBNL3_ROUTE
+#include <netlink/route/link.h>
+#include <netlink/route/link/macvlan.h>
+#include "macvlan.h"
+
+
+int macvlan_add(const char *if_name, const u8 *addr, const char *if_base)
+{
+	int err;
+	struct rtnl_link *link = NULL;
+	struct rtnl_link *base = NULL;
+	struct nl_addr *nl_addr = NULL;
+	struct nl_sock *handle = NULL;
+	int ret = -1;
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to open netlink socket");
+		goto macvlan_add_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to connect to netlink");
+		goto macvlan_add_error;
+	}
+
+	if (rtnl_link_get_kernel(handle, 0, if_base, &base) < 0) {
+		/* link does not exist */
+		wpa_printf(MSG_ERROR, "MACVLAN: interface %s does not exists",
+			   if_base);
+		goto macvlan_add_error;
+	}
+
+	link = rtnl_link_macvlan_alloc();
+	if (!link) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to allocate link");
+		goto macvlan_add_error;
+	}
+
+	err = rtnl_link_macvlan_set_mode(link,
+					 rtnl_link_macvlan_str2mode("bridge"));
+	if (err < 0) {
+		wpa_printf(MSG_ERROR,
+			   "MACVLAN: failed to set link type to macvlan");
+		goto macvlan_add_error;
+	}
+
+	nl_addr = nl_addr_build(AF_LLC, (void *) addr, ETH_ALEN);
+	if (!nl_addr) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to parse addr");
+		goto macvlan_add_error;
+	}
+	rtnl_link_set_addr(link, nl_addr);
+	nl_addr_put(nl_addr);
+
+	rtnl_link_set_name(link, if_name);
+
+	rtnl_link_set_link(link, rtnl_link_get_ifindex(base));
+
+	err = rtnl_link_add(handle, link, NLM_F_CREATE);
+	if (err < 0) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to create link");
+		goto macvlan_add_error;
+	}
+	ret = 0;
+
+macvlan_add_error:
+	if (link)
+		rtnl_link_put(link);
+
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
+
+
+int macvlan_del(const char *if_name)
+{
+	int ret = -1;
+	struct nl_sock *handle = NULL;
+	struct rtnl_link *rlink = NULL;
+
+	wpa_printf(MSG_DEBUG, "MACVLAN: macvlan_del(if_name=%s)", if_name);
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to open netlink socket");
+		goto macvlan_del_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to connect to netlink");
+		goto macvlan_del_error;
+	}
+
+	if (rtnl_link_get_kernel(handle, 0, if_name, &rlink) < 0) {
+		/* link does not exist */
+		wpa_printf(MSG_ERROR, "MACVLAN: interface %s does not exists",
+			   if_name);
+		goto macvlan_del_error;
+	}
+
+	if (rtnl_link_delete(handle, rlink) < 0) {
+		wpa_printf(MSG_ERROR, "MACVLAN: failed to remove link %s",
+			   if_name);
+		goto macvlan_del_error;
+	}
+
+	ret = 0;
+
+macvlan_del_error:
+	if (rlink)
+		rtnl_link_put(rlink);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
+#endif /* CONFIG_LIBNL3_ROUTE */
diff --git a/src/ap/macvlan.h b/src/ap/macvlan.h
new file mode 100644
index 0000000..c97373b
--- /dev/null
+++ b/src/ap/macvlan.h
@@ -0,0 +1,10 @@
+#ifndef HOSTAPD_MACVLAN_H
+#define HOSTAPD_MACVLAN_H
+
+#ifdef CONFIG_LIBNL3_ROUTE
+int macvlan_add(const char *if_name, const u8 *addr, const char *if_base);
+int macvlan_del(const char *if_name);
+#endif /* CONFIG_LIBNL3_ROUTE */
+
+#endif
+
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index fd1c4aa..da45433 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -28,6 +28,12 @@
 #include "ap_config.h"
 #include "wpa_auth.h"
 #include "wpa_auth_glue.h"
+#include <stdlib.h>
+
+#ifdef CONFIG_IEEE80211R_MACVLAN
+#include "macvlan.h"
+#include "vlan_ifconfig.h"
+#endif /* CONFIG_IEEE80211R_MACVLAN */
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
@@ -738,6 +744,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)
@@ -795,9 +804,28 @@ 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->iface;
+		if (hapd->conf->bridge[0])
+			ft_iface = hapd->conf->bridge;
+		if (hapd->conf->ft_iface[0]) {
+			ft_iface = hapd->conf->ft_iface;
+#ifdef CONFIG_IEEE80211R_MACVLAN
+			snprintf(hapd->conf->ft_macvlan,
+				 sizeof(hapd->conf->ft_macvlan),
+				 "ft%s", hapd->conf->iface);
+			if (macvlan_add(hapd->conf->ft_macvlan,
+					hapd->own_addr,	ft_iface) < 0 ||
+			    ifconfig_up(hapd->conf->ft_macvlan) < 0) {
+				wpa_printf(MSG_ERROR, "Failed to add bssid to "
+					   "ft_iface %s", ft_iface);
+				hapd->conf->ft_macvlan[0] = '\0';
+			} else
+				ft_iface = hapd->conf->ft_macvlan;
+		} else {
+			hapd->conf->ft_macvlan[0] = '\0';
+#endif /* CONFIG_IEEE80211R_MACVLAN */
+		}
+		hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
 					  hostapd_rrb_receive, hapd, 1);
 		if (hapd->l2 == NULL &&
 		    (hapd->driver == NULL ||
@@ -846,6 +874,12 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
 	ieee802_1x_deinit(hapd);
 
 #ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_MACVLAN
+	if (hapd->conf->ft_macvlan[0]) {
+		ifconfig_down(hapd->conf->ft_macvlan);
+		macvlan_del(hapd->conf->ft_macvlan);
+	}
+#endif /* CONFIG_IEEE80211R_MACVLAN */
 	l2_packet_deinit(hapd->l2);
 	hapd->l2 = NULL;
 #endif /* CONFIG_IEEE80211R */
-- 
2.1.4




More information about the Hostap mailing list