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 <netlink/route/link.h> 1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/route/link/vlan.h> 1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/common.h" 1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "vlan_util.h" 1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* 1761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and 1861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * tagged interface 'if_name'. 1961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 2061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns -1 on error 2161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 1 if the interface already exists 2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 0 otherwise 2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt*/ 2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_add(const char *if_name, int vid, const char *vlan_if_name) 2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 2605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt int err, ret = -1; 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_sock *handle = NULL; 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct rtnl_link *rlink = NULL; 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int if_idx = 0; 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "vlan_if_name=%s)", if_name, vid, vlan_if_name); 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((os_strlen(if_name) + 1) > IFNAMSIZ) { 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vlan_if_name); 4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 4461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt handle = nl_socket_alloc(); 4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!handle) { 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5205df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = nl_connect(handle, NETLINK_ROUTE); 5305df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 5405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", 5505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt nl_geterror(err)); 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 599c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt err = rtnl_link_get_kernel(handle, 0, if_name, &rlink); 6005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does not exist */ 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 669c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if_idx = rtnl_link_get_ifindex(rlink); 679c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt rtnl_link_put(rlink); 689c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt rlink = NULL; 6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 709c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink); 719c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if (err >= 0) { 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does exist */ 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rlink = NULL; 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", 7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt vlan_if_name); 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 1; 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rlink = rtnl_link_alloc(); 8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!rlink) { 8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); 8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = rtnl_link_set_type(rlink, "vlan"); 8805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 8905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s", 9005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt nl_geterror(err)); 9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 9461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_set_link(rlink, if_idx); 9561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_set_name(rlink, vlan_if_name); 9661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 9705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = rtnl_link_vlan_set_id(rlink, vid); 9805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 9905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s", 10005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt nl_geterror(err)); 10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = rtnl_link_add(handle, rlink, NLM_F_CREATE); 10505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " 10705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt "vlan %d on %s (%d): %s", 10805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt vlan_if_name, vid, if_name, if_idx, 10905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt nl_geterror(err)); 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_add_error; 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 0; 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_add_error: 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rlink) 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (handle) 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_socket_free(handle); 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return ret; 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_rem(const char *if_name) 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 12605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt int err, ret = -1; 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct nl_sock *handle = NULL; 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct rtnl_link *rlink = NULL; 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt handle = nl_socket_alloc(); 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!handle) { 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = nl_connect(handle, NETLINK_ROUTE); 13905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 14005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", 14105df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt nl_geterror(err)); 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1459c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt err = rtnl_link_get_kernel(handle, 0, if_name, &rlink); 14605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* link does not exist */ 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if_name); 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15305df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt err = rtnl_link_delete(handle, rlink); 15405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if (err < 0) { 15505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s", 15605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt if_name, nl_geterror(err)); 15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt goto vlan_rem_error; 15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ret = 0; 16161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_rem_error: 16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (rlink) 16461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rtnl_link_put(rlink); 16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (handle) 16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt nl_socket_free(handle); 16761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return ret; 16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 169e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt 170e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt 171e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidtint vlan_set_name_type(unsigned int name_type) 172e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt{ 173e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt return 0; 174e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt} 175