vlan_util.c revision 252190
1252190Srpaulo/* 2252190Srpaulo * hostapd / VLAN netlink api 3252190Srpaulo * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de> 4252190Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7252190Srpaulo */ 8252190Srpaulo 9252190Srpaulo#include "utils/includes.h" 10252190Srpaulo#include <sys/ioctl.h> 11252190Srpaulo#include <linux/sockios.h> 12252190Srpaulo#include <linux/if_vlan.h> 13252190Srpaulo#include <netlink/genl/genl.h> 14252190Srpaulo#include <netlink/genl/family.h> 15252190Srpaulo#include <netlink/genl/ctrl.h> 16252190Srpaulo#include <netlink/route/link.h> 17252190Srpaulo#include <netlink/route/link/vlan.h> 18252190Srpaulo 19252190Srpaulo#include "utils/common.h" 20252190Srpaulo#include "utils/eloop.h" 21252190Srpaulo#include "hostapd.h" 22252190Srpaulo#include "vlan_util.h" 23252190Srpaulo 24252190Srpaulo/* 25252190Srpaulo * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and 26252190Srpaulo * tagged interface 'if_name'. 27252190Srpaulo * 28252190Srpaulo * returns -1 on error 29252190Srpaulo * returns 1 if the interface already exists 30252190Srpaulo * returns 0 otherwise 31252190Srpaulo*/ 32252190Srpauloint vlan_add(const char *if_name, int vid, const char *vlan_if_name) 33252190Srpaulo{ 34252190Srpaulo int ret = -1; 35252190Srpaulo struct nl_sock *handle = NULL; 36252190Srpaulo struct nl_cache *cache = NULL; 37252190Srpaulo struct rtnl_link *rlink = NULL; 38252190Srpaulo int if_idx = 0; 39252190Srpaulo 40252190Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " 41252190Srpaulo "vlan_if_name=%s)", if_name, vid, vlan_if_name); 42252190Srpaulo 43252190Srpaulo if ((os_strlen(if_name) + 1) > IFNAMSIZ) { 44252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 45252190Srpaulo if_name); 46252190Srpaulo return -1; 47252190Srpaulo } 48252190Srpaulo 49252190Srpaulo if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { 50252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 51252190Srpaulo vlan_if_name); 52252190Srpaulo return -1; 53252190Srpaulo } 54252190Srpaulo 55252190Srpaulo handle = nl_socket_alloc(); 56252190Srpaulo if (!handle) { 57252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 58252190Srpaulo goto vlan_add_error; 59252190Srpaulo } 60252190Srpaulo 61252190Srpaulo if (nl_connect(handle, NETLINK_ROUTE) < 0) { 62252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 63252190Srpaulo goto vlan_add_error; 64252190Srpaulo } 65252190Srpaulo 66252190Srpaulo if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 67252190Srpaulo cache = NULL; 68252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 69252190Srpaulo goto vlan_add_error; 70252190Srpaulo } 71252190Srpaulo 72252190Srpaulo if (!(if_idx = rtnl_link_name2i(cache, if_name))) { 73252190Srpaulo /* link does not exist */ 74252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", 75252190Srpaulo if_name); 76252190Srpaulo goto vlan_add_error; 77252190Srpaulo } 78252190Srpaulo 79252190Srpaulo if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { 80252190Srpaulo /* link does exist */ 81252190Srpaulo rtnl_link_put(rlink); 82252190Srpaulo rlink = NULL; 83252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", 84252190Srpaulo vlan_if_name); 85252190Srpaulo ret = 1; 86252190Srpaulo goto vlan_add_error; 87252190Srpaulo } 88252190Srpaulo 89252190Srpaulo rlink = rtnl_link_alloc(); 90252190Srpaulo if (!rlink) { 91252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); 92252190Srpaulo goto vlan_add_error; 93252190Srpaulo } 94252190Srpaulo 95252190Srpaulo if (rtnl_link_set_type(rlink, "vlan") < 0) { 96252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); 97252190Srpaulo goto vlan_add_error; 98252190Srpaulo } 99252190Srpaulo 100252190Srpaulo rtnl_link_set_link(rlink, if_idx); 101252190Srpaulo rtnl_link_set_name(rlink, vlan_if_name); 102252190Srpaulo 103252190Srpaulo if (rtnl_link_vlan_set_id(rlink, vid) < 0) { 104252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); 105252190Srpaulo goto vlan_add_error; 106252190Srpaulo } 107252190Srpaulo 108252190Srpaulo if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { 109252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " 110252190Srpaulo "vlan %d on %s (%d)", 111252190Srpaulo vlan_if_name, vid, if_name, if_idx); 112252190Srpaulo goto vlan_add_error; 113252190Srpaulo } 114252190Srpaulo 115252190Srpaulo ret = 0; 116252190Srpaulo 117252190Srpaulovlan_add_error: 118252190Srpaulo if (rlink) 119252190Srpaulo rtnl_link_put(rlink); 120252190Srpaulo if (cache) 121252190Srpaulo nl_cache_free(cache); 122252190Srpaulo if (handle) 123252190Srpaulo nl_socket_free(handle); 124252190Srpaulo return ret; 125252190Srpaulo} 126252190Srpaulo 127252190Srpaulo 128252190Srpauloint vlan_rem(const char *if_name) 129252190Srpaulo{ 130252190Srpaulo int ret = -1; 131252190Srpaulo struct nl_sock *handle = NULL; 132252190Srpaulo struct nl_cache *cache = NULL; 133252190Srpaulo struct rtnl_link *rlink = NULL; 134252190Srpaulo 135252190Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); 136252190Srpaulo 137252190Srpaulo handle = nl_socket_alloc(); 138252190Srpaulo if (!handle) { 139252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 140252190Srpaulo goto vlan_rem_error; 141252190Srpaulo } 142252190Srpaulo 143252190Srpaulo if (nl_connect(handle, NETLINK_ROUTE) < 0) { 144252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 145252190Srpaulo goto vlan_rem_error; 146252190Srpaulo } 147252190Srpaulo 148252190Srpaulo if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 149252190Srpaulo cache = NULL; 150252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 151252190Srpaulo goto vlan_rem_error; 152252190Srpaulo } 153252190Srpaulo 154252190Srpaulo if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { 155252190Srpaulo /* link does not exist */ 156252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", 157252190Srpaulo if_name); 158252190Srpaulo goto vlan_rem_error; 159252190Srpaulo } 160252190Srpaulo 161252190Srpaulo if (rtnl_link_delete(handle, rlink) < 0) { 162252190Srpaulo wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", 163252190Srpaulo if_name); 164252190Srpaulo goto vlan_rem_error; 165252190Srpaulo } 166252190Srpaulo 167252190Srpaulo ret = 0; 168252190Srpaulo 169252190Srpaulovlan_rem_error: 170252190Srpaulo if (rlink) 171252190Srpaulo rtnl_link_put(rlink); 172252190Srpaulo if (cache) 173252190Srpaulo nl_cache_free(cache); 174252190Srpaulo if (handle) 175252190Srpaulo nl_socket_free(handle); 176252190Srpaulo return ret; 177252190Srpaulo} 178