From patchwork Thu Aug 9 09:55:06 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [v2,2/4] use netlink to create vlan interface From: michael-dev@fami-braun.de X-Patchwork-Id: 176040 Message-Id: <20120809095506.14256.86901.stgit@localhost6.localdomain6> To: hostap@lists.shmoo.com Cc: projekt-wlan@fem.tu-ilmenau.de Date: Thu, 09 Aug 2012 11:55:06 +0200 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 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 + + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#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 + + * 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)