161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* 261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * hostapd / VLAN netlink api 361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de> 461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * See README for more details. 761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/includes.h" 1061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <sys/ioctl.h> 1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <linux/sockios.h> 1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <linux/if_vlan.h> 1361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/genl/genl.h> 1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/genl/family.h> 1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/genl/ctrl.h> 1661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/route/link.h> 1761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/route/link/vlan.h> 1861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/common.h" 2061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/eloop.h" 2161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "hostapd.h" 2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "vlan_util.h" 2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* 2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * tagged interface 'if_name'. 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns -1 on error 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 1 if the interface already exists 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 0 otherwise 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt*/ 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_add(const char *if_name, int vid, const char *vlan_if_name) 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int ret = -1; 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_sock *handle = NULL; 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_cache *cache = NULL; 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct rtnl_link *rlink = NULL; 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int if_idx = 0; 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "vlan_if_name=%s)", if_name, vid, vlan_if_name); 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((os_strlen(if_name) + 1) > IFNAMSIZ) { 4461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vlan_if_name); 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 5361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 5461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt handle = nl_socket_alloc(); 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!handle) { 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (nl_connect(handle, NETLINK_ROUTE) < 0) { 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 6661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt cache = NULL; 6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!(if_idx = rtnl_link_name2i(cache, if_name))) { 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does not exist */ 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { 8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does exist */ 8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rlink = NULL; 8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", 8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vlan_if_name); 8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 1; 8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 8761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 8861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rlink = rtnl_link_alloc(); 9061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!rlink) { 9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); 9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 9461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 9561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_set_type(rlink, "vlan") < 0) { 9661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); 9761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 9861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 9961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_set_link(rlink, if_idx); 10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_set_name(rlink, vlan_if_name); 10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_vlan_set_id(rlink, vid) < 0) { 10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); 10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { 10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "vlan %d on %s (%d)", 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vlan_if_name, vid, if_name, if_idx); 11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 0; 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_add_error: 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rlink) 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (cache) 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_cache_free(cache); 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (handle) 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_socket_free(handle); 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return ret; 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_rem(const char *if_name) 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int ret = -1; 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_sock *handle = NULL; 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_cache *cache = NULL; 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct rtnl_link *rlink = NULL; 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt handle = nl_socket_alloc(); 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!handle) { 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (nl_connect(handle, NETLINK_ROUTE) < 0) { 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt cache = NULL; 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { 15561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does not exist */ 15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", 15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rtnl_link_delete(handle, rlink) < 0) { 16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", 16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 16461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 0; 16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_rem_error: 17061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rlink) 17161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 17261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (cache) 17361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_cache_free(cache); 17461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (handle) 17561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_socket_free(handle); 17661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return ret; 17761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 178