[PATCH] macvlan: ft_iface and rsn_preauth_interfaces can be shared

Michael Braun michael-dev at fami-braun.de
Mon Sep 26 13:08:04 PDT 2016


Macvlan does not permit multiple BRIDGE type interfaces on the same lowerdev to
share their mac address.

So in order to share the lowerdev of the macvlan interfaces required by
ft_iface and rsn_preauth_interfaces, they need to share their macvlan interface
as well.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 hostapd/Makefile       |   1 +
 src/ap/hostapd.h       |   3 ++
 src/ap/macvlan.c       | 141 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/ap/macvlan.h       |  16 +++++-
 src/ap/preauth_auth.c  |   5 +-
 src/ap/wpa_auth_glue.c |   6 ++-
 6 files changed, 162 insertions(+), 10 deletions(-)

diff --git a/hostapd/Makefile b/hostapd/Makefile
index 349d302..158fb6e 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -867,6 +867,7 @@ endif
 ifdef NEED_MACVLAN
 ifdef CONFIG_LIBNL32
 ifdef CONFIG_LIBNL3_ROUTE
+CFLAGS += -DCONFIG_NEED_MACVLAN
 OBJS += ../src/ap/macvlan.o
 LIBS += -lnl-3
 LIBS += -lnl-genl-3
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 22aa6fa..74919a2 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_NEED_MACVLAN
+	struct macvlan_iface *macvlan_priv;
+#endif /* CONFIG_NEED_MACVLAN */
 	int eloop_initialized;
 };
 
diff --git a/src/ap/macvlan.c b/src/ap/macvlan.c
index 683d632..06fdb9f 100644
--- a/src/ap/macvlan.c
+++ b/src/ap/macvlan.c
@@ -7,16 +7,109 @@
  */
 
 #include "utils/includes.h"
-
 #include "utils/common.h"
+#include "hostapd.h"
 
 #ifdef CONFIG_LIBNL3_ROUTE
 #include <netlink/route/link.h>
 #include <netlink/route/link/macvlan.h>
+#endif /* CONFIG_LIBNL3_ROUTE */
+
 #include "macvlan.h"
 
 
-int macvlan_add(const char *if_name, const u8 *addr, const char *if_base)
+struct macvlan_iface {
+	char if_name[IFNAMSIZ + 1];
+	char if_base[IFNAMSIZ + 1];
+	u8 addr[ETH_ALEN];
+	int usage;
+	struct macvlan_iface *next;
+};
+
+
+/* Increment ref counter for if_name */
+static struct macvlan_iface * macvlan_list_get(struct hostapd_data *hapd,
+					       const char *if_base,
+					       const u8 *addr)
+{
+	struct macvlan_iface *next, **macvlan_ifaces;
+	struct hapd_interfaces *interfaces;
+
+	interfaces = hapd->iface->interfaces;
+	macvlan_ifaces = &interfaces->macvlan_priv;
+
+	for (next = *macvlan_ifaces; next; next = next->next) {
+		if (os_strcmp(if_base, next->if_base) == 0 &&
+		    os_memcmp(addr, next->addr, sizeof(next->addr)) == 0)
+			break;
+	}
+
+	if (next)
+		next->usage++;
+
+	return next;
+}
+
+
+static void macvlan_list_add(struct hostapd_data *hapd, const char *if_name,
+			     const char *if_base, const u8 *addr)
+{
+	struct macvlan_iface *next, **macvlan_ifaces;
+	struct hapd_interfaces *interfaces;
+
+	interfaces = hapd->iface->interfaces;
+	macvlan_ifaces = &interfaces->macvlan_priv;
+
+	next = os_zalloc(sizeof(*next));
+	if (!next)
+		return;
+
+	os_strlcpy(next->if_name, if_name, sizeof(next->if_name));
+	os_strlcpy(next->if_base, if_base, sizeof(next->if_base));
+	os_memcpy(next->addr, addr, sizeof(next->addr));
+	next->usage = 1;
+	next->next = *macvlan_ifaces;
+	*macvlan_ifaces = next;
+}
+
+
+/* Decrement reference counter for given if_name.
+ * Return 1 iff reference counter was decreased to zero, else zero
+ */
+static int macvlan_list_put(struct hostapd_data *hapd, const char *if_name)
+{
+	struct macvlan_iface *next, *prev = NULL, **macvlan_ifaces;
+	struct hapd_interfaces *interfaces;
+
+	interfaces = hapd->iface->interfaces;
+	macvlan_ifaces = &interfaces->macvlan_priv;
+
+	for (next = *macvlan_ifaces; next; next = next->next) {
+		if (os_strcmp(if_name, next->if_name) == 0)
+			break;
+		prev = next;
+	}
+
+	if (!next)
+		return 0;
+
+	next->usage--;
+	if (next->usage)
+		return 0;
+
+	if (prev)
+		prev->next = next->next;
+	else
+		*macvlan_ifaces = next->next;
+	os_free(next);
+
+	return 1;
+}
+
+
+#ifdef CONFIG_LIBNL3_ROUTE
+static int macvlan_iface_add(const char *if_name, const u8 *addr,
+			     const char *if_base)
 {
 	int err;
 	struct rtnl_link *link = NULL;
@@ -86,13 +179,14 @@ macvlan_add_error:
 }
 
 
-int macvlan_del(const char *if_name)
+static int macvlan_iface_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);
+	wpa_printf(MSG_DEBUG, "MACVLAN: macvlan_iface_del(if_name=%s)",
+		   if_name);
 
 	handle = nl_socket_alloc();
 	if (!handle) {
@@ -128,3 +222,42 @@ macvlan_del_error:
 	return ret;
 }
 #endif /* CONFIG_LIBNL3_ROUTE */
+
+
+/* create or reuse macvlan interface
+ * @param if_name proposed name, may be altered if required
+ * @param addr mac-address
+ * @param if_base macvlan lowerdev
+ *
+ * @returns 0 on success, negative error code else
+ */
+int macvlan_add(struct hostapd_data *hapd, char *if_name, size_t len,
+		const u8 *addr, const char *if_base)
+{
+	struct macvlan_iface *info;
+	int ret;
+
+	info = macvlan_list_get(hapd, if_base, addr);
+
+	if (info) {
+		os_strlcpy(if_name, info->if_name, len);
+		return 0;
+	}
+
+	ret = macvlan_iface_add(if_name, addr, if_base);
+	if (ret == 0)
+		macvlan_list_add(hapd, if_name, if_base, addr);
+
+	return ret;
+}
+
+
+int macvlan_del(struct hostapd_data *hapd, const char *if_name)
+{
+	wpa_printf(MSG_DEBUG, "MACVLAN: macvlan_del(if_name=%s)", if_name);
+
+	if (macvlan_list_put(hapd, if_name))
+		return macvlan_iface_del(if_name);
+	else
+		return 0;
+}
diff --git a/src/ap/macvlan.h b/src/ap/macvlan.h
index c97373b..49f91f9 100644
--- a/src/ap/macvlan.h
+++ b/src/ap/macvlan.h
@@ -2,8 +2,20 @@
 #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);
+
+/* create or reuse macvlan interface if_name
+ * @param if_name  macvlan interface name, may be altered
+ * @param len      size of if_name buffer
+ * @param addr     hw ether address
+ * @param if_base  macvlan lowerdev
+ *
+ * @returns negative error code or 0 on success
+ */
+int macvlan_add(struct hostapd_data *hapd, char *if_name, size_t len,
+		const u8 *addr, const char *if_base);
+
+int macvlan_del(struct hostapd_data *hapd, const char *if_name);
+
 #endif /* CONFIG_LIBNL3_ROUTE */
 
 #endif
diff --git a/src/ap/preauth_auth.c b/src/ap/preauth_auth.c
index 7ff4323..835f0bc 100644
--- a/src/ap/preauth_auth.c
+++ b/src/ap/preauth_auth.c
@@ -140,7 +140,8 @@ static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname,
 #ifdef CONFIG_RSN_PREAUTH_MACVLAN
 	snprintf(macvlan_iface, sizeof(macvlan_iface), "pre%d%s",
 		 idx, hapd->conf->iface);
-	if (macvlan_add(macvlan_iface, hapd->own_addr, ifname) < 0 ||
+	if (macvlan_add(hapd, macvlan_iface, sizeof(macvlan_iface),
+			hapd->own_addr, ifname) < 0 ||
 	    ifconfig_up(macvlan_iface) < 0) {
 		wpa_printf(MSG_ERROR, "Failed to add bssid to "
 			   "rsn_preauth_interface %s", ifname);
@@ -188,7 +189,7 @@ void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
 #ifdef CONFIG_RSN_PREAUTH_MACVLAN
 		if (prev->is_macvlan) {
 			ifconfig_down(prev->ifname);
-			macvlan_del(prev->ifname);
+			macvlan_del(hapd, prev->ifname);
 		}
 #endif /* CONFIG_RSN_PREAUTH_MACVLAN */
 		l2_packet_deinit(prev->l2);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 2d80714..7161913 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1045,7 +1045,9 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 			snprintf(hapd->conf->ft_macvlan,
 				 sizeof(hapd->conf->ft_macvlan),
 				 "ft%s", hapd->conf->iface);
-			if (macvlan_add(hapd->conf->ft_macvlan,
+			if (macvlan_add(hapd,
+					hapd->conf->ft_macvlan,
+					sizeof(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 "
@@ -1109,7 +1111,7 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
 #ifdef CONFIG_IEEE80211R_MACVLAN
 	if (hapd->conf->ft_macvlan[0]) {
 		ifconfig_down(hapd->conf->ft_macvlan);
-		macvlan_del(hapd->conf->ft_macvlan);
+		macvlan_del(hapd, hapd->conf->ft_macvlan);
 	}
 #endif /* CONFIG_IEEE80211R_MACVLAN */
 	l2_packet_deinit(hapd->l2);
-- 
2.1.4




More information about the Hostap mailing list