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 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 if (nl_connect(handle, NETLINK_ROUTE) < 0) { 62 wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 63 goto vlan_add_error; 64 } 65 66 if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 67 cache = NULL; 68 wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 69 goto vlan_add_error; 70 } 71 72 if (!(if_idx = rtnl_link_name2i(cache, if_name))) { 73 /* link does not exist */ 74 wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", 75 if_name); 76 goto vlan_add_error; 77 } 78 79 if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { 80 /* link does exist */ 81 rtnl_link_put(rlink); 82 rlink = NULL; 83 wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", 84 vlan_if_name); 85 ret = 1; 86 goto vlan_add_error; 87 } 88 89 rlink = rtnl_link_alloc(); 90 if (!rlink) { 91 wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); 92 goto vlan_add_error; 93 } 94 95 if (rtnl_link_set_type(rlink, "vlan") < 0) { 96 wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); 97 goto vlan_add_error; 98 } 99 100 rtnl_link_set_link(rlink, if_idx); 101 rtnl_link_set_name(rlink, vlan_if_name); 102 103 if (rtnl_link_vlan_set_id(rlink, vid) < 0) { 104 wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); 105 goto vlan_add_error; 106 } 107 108 if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { 109 wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " 110 "vlan %d on %s (%d)", 111 vlan_if_name, vid, if_name, if_idx); 112 goto vlan_add_error; 113 } 114 115 ret = 0; 116 117 vlan_add_error: 118 if (rlink) 119 rtnl_link_put(rlink); 120 if (cache) 121 nl_cache_free(cache); 122 if (handle) 123 nl_socket_free(handle); 124 return ret; 125 } 126 127 128 int vlan_rem(const char *if_name) 129 { 130 int ret = -1; 131 struct nl_sock *handle = NULL; 132 struct nl_cache *cache = NULL; 133 struct rtnl_link *rlink = NULL; 134 135 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); 136 137 handle = nl_socket_alloc(); 138 if (!handle) { 139 wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); 140 goto vlan_rem_error; 141 } 142 143 if (nl_connect(handle, NETLINK_ROUTE) < 0) { 144 wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); 145 goto vlan_rem_error; 146 } 147 148 if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { 149 cache = NULL; 150 wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); 151 goto vlan_rem_error; 152 } 153 154 if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { 155 /* link does not exist */ 156 wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", 157 if_name); 158 goto vlan_rem_error; 159 } 160 161 if (rtnl_link_delete(handle, rlink) < 0) { 162 wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", 163 if_name); 164 goto vlan_rem_error; 165 } 166 167 ret = 0; 168 169 vlan_rem_error: 170 if (rlink) 171 rtnl_link_put(rlink); 172 if (cache) 173 nl_cache_free(cache); 174 if (handle) 175 nl_socket_free(handle); 176 return ret; 177 } 178