1 /* 2 * hostapd / VLAN netlink api 3 * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 #include <sys/ioctl.h> 11 #include <linux/sockios.h> 12 #include <linux/if_vlan.h> 13 #include <netlink/genl/genl.h> 14 #include <netlink/genl/family.h> 15 #include <netlink/genl/ctrl.h> 16 #include <netlink/route/link.h> 17 #include <netlink/route/link/vlan.h> 18 19 #include "utils/common.h" 20 #include "utils/eloop.h" 21 #include "hostapd.h" 22 #include "vlan_util.h" 23 24 /* 25 * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and 26 * tagged interface 'if_name'. 27 * 28 * returns -1 on error 29 * returns 1 if the interface already exists 30 * returns 0 otherwise 31 */ 32 int vlan_add(const char *if_name, int vid, const char *vlan_if_name) 33 { 34 int err, ret = -1; 35 struct nl_sock *handle = NULL; 36 struct nl_cache *cache = NULL; 37 struct rtnl_link *rlink = NULL; 38 int if_idx = 0; 39 40 wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " 41 "vlan_if_name=%s)", if_name, vid, vlan_if_name); 42 43 if ((os_strlen(if_name) + 1) > IFNAMSIZ) { 44 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 45 if_name); 46 return -1; 47 } 48 49 if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { 50 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 51 vlan_if_name); 52 return -1; 53 } 54 55 handle = nl_socket_alloc(); 56 if (!handle) { 57 wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 58 goto vlan_add_error; 59 } 60 61 err = nl_connect(handle, NETLINK_ROUTE); 62 if (err < 0) { 63 wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", 64 nl_geterror(err)); 65 goto vlan_add_error; 66 } 67 68 err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache); 69 if (err < 0) { 70 cache = NULL; 71 wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s", 72 nl_geterror(err)); 73 goto vlan_add_error; 74 } 75 76 if (!(if_idx = rtnl_link_name2i(cache, if_name))) { 77 /* link does not exist */ 78 wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", 79 if_name); 80 goto vlan_add_error; 81 } 82 83 if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { 84 /* link does exist */ 85 rtnl_link_put(rlink); 86 rlink = NULL; 87 wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", 88 vlan_if_name); 89 ret = 1; 90 goto vlan_add_error; 91 } 92 93 rlink = rtnl_link_alloc(); 94 if (!rlink) { 95 wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); 96 goto vlan_add_error; 97 } 98 99 err = rtnl_link_set_type(rlink, "vlan"); 100 if (err < 0) { 101 wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s", 102 nl_geterror(err)); 103 goto vlan_add_error; 104 } 105 106 rtnl_link_set_link(rlink, if_idx); 107 rtnl_link_set_name(rlink, vlan_if_name); 108 109 err = rtnl_link_vlan_set_id(rlink, vid); 110 if (err < 0) { 111 wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s", 112 nl_geterror(err)); 113 goto vlan_add_error; 114 } 115 116 err = rtnl_link_add(handle, rlink, NLM_F_CREATE); 117 if (err < 0) { 118 wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " 119 "vlan %d on %s (%d): %s", 120 vlan_if_name, vid, if_name, if_idx, 121 nl_geterror(err)); 122 goto vlan_add_error; 123 } 124 125 ret = 0; 126 127 vlan_add_error: 128 if (rlink) 129 rtnl_link_put(rlink); 130 if (cache) 131 nl_cache_free(cache); 132 if (handle) 133 nl_socket_free(handle); 134 return ret; 135 } 136 137 138 int vlan_rem(const char *if_name) 139 { 140 int err, ret = -1; 141 struct nl_sock *handle = NULL; 142 struct nl_cache *cache = NULL; 143 struct rtnl_link *rlink = NULL; 144 145 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); 146 147 handle = nl_socket_alloc(); 148 if (!handle) { 149 wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 150 goto vlan_rem_error; 151 } 152 153 err = nl_connect(handle, NETLINK_ROUTE); 154 if (err < 0) { 155 wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s", 156 nl_geterror(err)); 157 goto vlan_rem_error; 158 } 159 160 err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache); 161 if (err < 0) { 162 cache = NULL; 163 wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s", 164 nl_geterror(err)); 165 goto vlan_rem_error; 166 } 167 168 if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { 169 /* link does not exist */ 170 wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", 171 if_name); 172 goto vlan_rem_error; 173 } 174 175 err = rtnl_link_delete(handle, rlink); 176 if (err < 0) { 177 wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s", 178 if_name, nl_geterror(err)); 179 goto vlan_rem_error; 180 } 181 182 ret = 0; 183 184 vlan_rem_error: 185 if (rlink) 186 rtnl_link_put(rlink); 187 if (cache) 188 nl_cache_free(cache); 189 if (handle) 190 nl_socket_free(handle); 191 return ret; 192 } 193