Patchwork [v2,2/4] use netlink to create vlan interface

login
register
mail settings
Submitter michael-dev@fami-braun.de
Date Aug. 9, 2012, 9:55 a.m.
Message ID <20120809095506.14256.86901.stgit@localhost6.localdomain6>
Download mbox | patch
Permalink /patch/176040/
State Accepted
Headers show

Comments

michael-dev@fami-braun.de - Aug. 9, 2012, 9:55 a.m.
This permits hostapd to set the name of the created interface.
---
 hostapd/Android.mk      |    1 
 hostapd/Makefile        |    1 
 src/ap/vlan_init.c      |  131 ++++++-----------------------------------------
 src/ap/vlan_util.c      |  129 ++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/vlan_util.h      |   14 +++++
 src/drivers/drivers.mak |   20 +++++++
 src/drivers/drivers.mk  |   21 ++++++++
 7 files changed, 204 insertions(+), 113 deletions(-)
 create mode 100644 src/ap/vlan_util.c
 create mode 100644 src/ap/vlan_util.h

Patch

diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 543c152..3ba6d47 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -151,6 +151,7 @@  ifdef CONFIG_NO_VLAN
 L_CFLAGS += -DCONFIG_NO_VLAN
 else
 OBJS += src/ap/vlan_init.c
+OBJS += src/ap/vlan_util.c
 endif
 
 ifdef CONFIG_NO_CTRL_IFACE
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 446210f..fff6894 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -123,6 +123,7 @@  ifdef CONFIG_NO_VLAN
 CFLAGS += -DCONFIG_NO_VLAN
 else
 OBJS += ../src/ap/vlan_init.o
+OBJS += ../src/ap/vlan_util.o
 endif
 
 ifdef CONFIG_NO_CTRL_IFACE
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index f2f766f..b1e8f42 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -21,6 +21,7 @@ 
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "vlan_init.h"
+#include "vlan_util.h"
 
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -370,117 +371,13 @@  static int vlan_rem(const char *if_name)
 }
 
 
-/*
-	Add a vlan interface with VLAN ID 'vid' and tagged interface
-	'if_name'.
-
-	returns -1 on error
-	returns 1 if the interface already exists
-	returns 0 otherwise
-*/
-static int vlan_add(const char *if_name, int vid)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-
-	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
-		   if_name, vid);
-	ifconfig_up(if_name);
-
-	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
-		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
-			   if_name);
-		return -1;
-	}
-
-	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-			   "failed: %s", __func__, strerror(errno));
-		return -1;
-	}
-
-	os_memset(&if_request, 0, sizeof(if_request));
-
-	/* Determine if a suitable vlan device already exists. */
-
-	os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
-		    vid);
-
-	if_request.cmd = _GET_VLAN_VID_CMD;
-
-	if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
-
-		if (if_request.u.VID == vid) {
-			if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
-
-			if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
-			    os_strncmp(if_request.u.device2, if_name,
-				       sizeof(if_request.u.device2)) == 0) {
-				close(fd);
-				wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
-					   "if_name %s exists already",
-					   if_request.device1);
-				return 1;
-			}
-		}
-	}
-
-	/* A suitable vlan device does not already exist, add one. */
-
-	os_memset(&if_request, 0, sizeof(if_request));
-	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
-	if_request.u.VID = vid;
-	if_request.cmd = ADD_VLAN_CMD;
-
-	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
-		wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
-			   "%s",
-			   __func__, if_request.device1, strerror(errno));
-		close(fd);
-		return -1;
-	}
-
-	close(fd);
-	return 0;
-}
-
-
-static int vlan_set_name_type(unsigned int name_type)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-
-	wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
-		   name_type);
-	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
-			   "failed: %s", __func__, strerror(errno));
-		return -1;
-	}
-
-	os_memset(&if_request, 0, sizeof(if_request));
-
-	if_request.u.name_type = name_type;
-	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
-	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
-		wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
-			   "name_type=%u failed: %s",
-			   __func__, name_type, strerror(errno));
-		close(fd);
-		return -1;
-	}
-
-	close(fd);
-	return 0;
-}
-
-
 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
 	char vlan_ifname[IFNAMSIZ];
 	char br_name[IFNAMSIZ];
 	struct hostapd_vlan *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int vlan_naming = hapd->conf->ssid.vlan_naming;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
@@ -497,11 +394,16 @@  static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 
 			if (tagged_interface) {
 
-				if (!vlan_add(tagged_interface, vlan->vlan_id))
-					vlan->clean |= DVLAN_CLEAN_VLAN;
+				if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+					os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+						    "%s.%d", tagged_interface, vlan->vlan_id);
+ 				else
+					os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+						    "vlan%d", vlan->vlan_id);
 
-				os_snprintf(vlan_ifname, sizeof(vlan_ifname),
-					    "vlan%d", vlan->vlan_id);
+				ifconfig_up(tagged_interface);
+				if (!vlan_add(tagged_interface, vlan->vlan_id, vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN;
 
 				if (!br_addif(br_name, vlan_ifname))
 					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
@@ -527,6 +429,7 @@  static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 	char br_name[IFNAMSIZ];
 	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int vlan_naming = hapd->conf->ssid.vlan_naming;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
 
@@ -541,8 +444,12 @@  static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 				br_delif(br_name, vlan->ifname);
 
 			if (tagged_interface) {
-				os_snprintf(vlan_ifname, sizeof(vlan_ifname),
-					    "vlan%d", vlan->vlan_id);
+				if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+					os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+						    "%s.%d", tagged_interface, vlan->vlan_id);
+ 				else
+					os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+						    "vlan%d", vlan->vlan_id);
 				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
 					br_delif(br_name, vlan_ifname);
 				ifconfig_down(vlan_ifname);
@@ -682,8 +589,6 @@  full_dynamic_vlan_init(struct hostapd_data *hapd)
 	if (priv == NULL)
 		return NULL;
 
-	vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
-
 	priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 	if (priv->s < 0) {
 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
new file mode 100644
index 0000000..3c2ccc8
--- /dev/null
+++ b/src/ap/vlan_util.c
@@ -0,0 +1,129 @@ 
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ 
+ * 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 "hostapd.h"
+#include "vlan_util.h"
+
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+#include "utils/eloop.h"
+
+
+/*
+	Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
+        tagged interface 'if_name'.
+
+	returns -1 on error
+	returns 1 if the interface already exists
+	returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char* vlan_if_name)
+{
+	int ret = -1;
+	struct nl_sock *handle = 0;
+	struct nl_cache *cache = 0;
+	struct rtnl_link *link = 0;
+	int if_idx = 0;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, vlan_if_name=%s)",
+		   if_name, vid, vlan_if_name);
+
+	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   if_name);
+		return -1;
+	}
+
+	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   vlan_if_name);
+		return -1;
+	}
+
+	handle = nl_socket_alloc();
+	if (!handle) { 
+		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+		goto vlan_add_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+		cache = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+		goto vlan_add_error;
+	}
+
+	if (!(if_idx = rtnl_link_name2i(cache, if_name))) {;
+		/* link does not exist */
+		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", if_name);
+		goto vlan_add_error;
+	}
+
+	if ((link = rtnl_link_get_by_name(cache, vlan_if_name))) {
+		/* link does exist */
+		rtnl_link_put(link); link = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", vlan_if_name);
+		ret = 1;
+		goto vlan_add_error;
+	}
+
+	link = rtnl_link_alloc();
+	if (!link) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_set_type(link, "vlan") < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+		goto vlan_add_error;
+	}
+
+	rtnl_link_set_link(link, if_idx);
+	rtnl_link_set_name(link, vlan_if_name);
+
+	if (rtnl_link_vlan_set_id(link, vid) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_add(handle, link, NLM_F_CREATE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for vlan %d on %s (%d)", vlan_if_name, vid, if_name, if_idx);
+		goto vlan_add_error;
+	}
+
+	ret = 0;
+
+vlan_add_error:
+	if (link)
+		rtnl_link_put(link);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
+
+#endif
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
new file mode 100644
index 0000000..673c546
--- /dev/null
+++ b/src/ap/vlan_util.h
@@ -0,0 +1,14 @@ 
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ 
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_UTIL_H
+#define VLAN_UTIL_H
+
+int vlan_add(const char *if_name, int vid, const char* vlan_if_name);
+
+#endif
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 0cc81f9..c2e53ab 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -142,6 +142,26 @@  ifdef NEED_RFKILL
 DRV_OBJS += ../src/drivers/rfkill.o
 endif
 
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
 
 ##### COMMON VARS
 DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 1d7129c..0ec1c55 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -146,6 +146,27 @@  ifdef CONFIG_DRIVER_CUSTOM
 DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
 endif
 
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+
 ##### COMMON VARS
 DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
 DRV_WPA_CFLAGS += $(DRV_CFLAGS)