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