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

login
register
mail settings
Submitter michael-dev@fami-braun.de
Date July 7, 2012, 8:52 a.m.
Message ID <20120707085212.24229.73047.stgit@localhost6.localdomain6>
Download mbox | patch
Permalink /patch/169568/
State Superseded
Headers show

Comments

michael-dev@fami-braun.de - July 7, 2012, 8:52 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      |  137 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/vlan_util.h      |   21 +++++++
 src/drivers/drivers.mak |   20 +++++++
 src/drivers/drivers.mk  |   21 +++++++
 7 files changed, 219 insertions(+), 113 deletions(-)
 create mode 100644 src/ap/vlan_util.c
 create mode 100644 src/ap/vlan_util.h
michael-dev@fami-braun.de - July 7, 2012, 8:56 a.m.
Hi,

Am 07.07.2012 10:52, schrieb Michael Braun:
> This permits hostapd to set the name of the created interface.
> ---
>  src/ap/vlan_util.c      |  137

the reason for moving vlan_add/vlan_rem into this new file is that the 
netlink/link.h and net/if.h headers conflict.

http://lists.infradead.org/pipermail/libnl/2012-April/000552.html

Regards,
  M. Braun
Jouni Malinen - Aug. 4, 2012, 6:05 p.m.
On Sat, Jul 07, 2012 at 10:52:12AM +0200, Michael Braun wrote:
> This permits hostapd to set the name of the created interface.

One question about the copyright and license statements in the new files
that needs to be addressed before I can apply these:

> diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
> new file mode 100644
> index 0000000..ca18963
> --- /dev/null
> +++ b/src/ap/vlan_util.c
> @@ -0,0 +1,137 @@
> +/*
> + * hostapd / VLAN initialization
> + * Copyright 2003, Instant802 Networks, Inc.
> + * Copyright 2005-2006, Devicescape Software, Inc.
> + * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Alternatively, this software may be distributed under the terms of BSD
> + * license.
> + *
> + * See README and COPYING for more details.
> + */


This copyright notice and license statement do not look correct. Isn't
this (and same for vlan_util.h) new code? If so, there is not much point
in copying the copyright statements from vlan_init.c. In addition, any
new files needs to use the BSD license language (i.e., drop the GPLv2
alternative):

 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
michael-dev@fami-braun.de - Aug. 9, 2012, 9:54 a.m.
These patches make hostapd use the netlink api to create and remove vlan
interfaces instead of the old kernel api.
This removes the dependency from the system global linux vlan interface name
type. It thus avoids conflicts with other applications, that can result in
a non-usable network configuration, as the new vlan interfaces won't be added
into the brige (due to the expected name being different from the actual name).

v2: update licence header

Signed-hostap: M. Braun <michael-dev@fami-braun.de>

---

Michael Braun (4):
      add configure option to set vlan naming scheme
      use netlink to create vlan interface
      use netlink to remove vlan interface
      remove obsolete include to kernel vlan api


 hostapd/Android.mk      |    1 
 hostapd/Makefile        |    1 
 hostapd/config_file.c   |    9 ++
 hostapd/hostapd.conf    |    6 ++
 src/ap/ap_config.h      |    4 +
 src/ap/vlan_init.c      |  167 +++++--------------------------------------
 src/ap/vlan_util.c      |  181 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/vlan_util.h      |   15 ++++
 src/drivers/drivers.mak |   20 +++++
 src/drivers/drivers.mk  |   21 +++++
 10 files changed, 276 insertions(+), 149 deletions(-)
 create mode 100644 src/ap/vlan_util.c
 create mode 100644 src/ap/vlan_util.h
Jouni Malinen - Aug. 10, 2012, 11:13 a.m.
On Thu, Aug 09, 2012 at 11:54:56AM +0200, Michael Braun wrote:
> These patches make hostapd use the netlink api to create and remove vlan
> interfaces instead of the old kernel api.
> This removes the dependency from the system global linux vlan interface name
> type. It thus avoids conflicts with other applications, that can result in
> a non-usable network configuration, as the new vlan interfaces won't be added
> into the brige (due to the expected name being different from the actual name).

Thanks, applied with changes described below.

This seems to depend on libnl 3.1 or newer which is somewhat of an
unfortunate dependency to add since it breaks hostapd builds on most
existing platforms.. I added this as an optional build parameter instead
of replacement of the ioctl-based calls.

If the global parameter is fine (and why wouldn't it be?), it looks like
the ioctl-based interface can still be used with this in
full_dynamic_vlan_init():

-	vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+	vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+			   DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+			   VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+			   VLAN_NAME_TYPE_PLUS_VID_NO_PAD);


If that is not enough, adding CONFIG_VLAN_NETLINK=y into hostapd/.config
will replace the kernel API to netlink (with the cost of having to have
a suitable libnl version available).

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 b43aa75..a734968 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..ca18963
--- /dev/null
+++ b/src/ap/vlan_util.c
@@ -0,0 +1,137 @@ 
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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..1fd146a
--- /dev/null
+++ b/src/ap/vlan_util.h
@@ -0,0 +1,21 @@ 
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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)