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 <netlink/route/link.h>
11#include <netlink/route/link/vlan.h>
12
13#include "utils/common.h"
14#include "vlan_util.h"
15
16/*
17 * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
18 * tagged interface 'if_name'.
19 *
20 * returns -1 on error
21 * returns 1 if the interface already exists
22 * returns 0 otherwise
23*/
24int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
25{
26	int err, ret = -1;
27	struct nl_sock *handle = NULL;
28	struct rtnl_link *rlink = NULL;
29	int if_idx = 0;
30
31	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
32		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
33
34	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
35		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
36			   if_name);
37		return -1;
38	}
39
40	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
41		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
42			   vlan_if_name);
43		return -1;
44	}
45
46	handle = nl_socket_alloc();
47	if (!handle) {
48		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
49		goto vlan_add_error;
50	}
51
52	err = nl_connect(handle, NETLINK_ROUTE);
53	if (err < 0) {
54		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
55			   nl_geterror(err));
56		goto vlan_add_error;
57	}
58
59	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
60	if (err < 0) {
61		/* link does not exist */
62		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
63			   if_name);
64		goto vlan_add_error;
65	}
66	if_idx = rtnl_link_get_ifindex(rlink);
67	rtnl_link_put(rlink);
68	rlink = NULL;
69
70	err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
71	if (err >= 0) {
72		/* link does exist */
73		rtnl_link_put(rlink);
74		rlink = NULL;
75		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
76			   vlan_if_name);
77		ret = 1;
78		goto vlan_add_error;
79	}
80
81	rlink = rtnl_link_alloc();
82	if (!rlink) {
83		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
84		goto vlan_add_error;
85	}
86
87	err = rtnl_link_set_type(rlink, "vlan");
88	if (err < 0) {
89		wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
90			   nl_geterror(err));
91		goto vlan_add_error;
92	}
93
94	rtnl_link_set_link(rlink, if_idx);
95	rtnl_link_set_name(rlink, vlan_if_name);
96
97	err = rtnl_link_vlan_set_id(rlink, vid);
98	if (err < 0) {
99		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
100			   nl_geterror(err));
101		goto vlan_add_error;
102	}
103
104	err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
105	if (err < 0) {
106		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
107			   "vlan %d on %s (%d): %s",
108			   vlan_if_name, vid, if_name, if_idx,
109			   nl_geterror(err));
110		goto vlan_add_error;
111	}
112
113	ret = 0;
114
115vlan_add_error:
116	if (rlink)
117		rtnl_link_put(rlink);
118	if (handle)
119		nl_socket_free(handle);
120	return ret;
121}
122
123
124int vlan_rem(const char *if_name)
125{
126	int err, ret = -1;
127	struct nl_sock *handle = NULL;
128	struct rtnl_link *rlink = NULL;
129
130	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
131
132	handle = nl_socket_alloc();
133	if (!handle) {
134		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
135		goto vlan_rem_error;
136	}
137
138	err = nl_connect(handle, NETLINK_ROUTE);
139	if (err < 0) {
140		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
141			   nl_geterror(err));
142		goto vlan_rem_error;
143	}
144
145	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
146	if (err < 0) {
147		/* link does not exist */
148		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
149			   if_name);
150		goto vlan_rem_error;
151	}
152
153	err = rtnl_link_delete(handle, rlink);
154	if (err < 0) {
155		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
156			   if_name, nl_geterror(err));
157		goto vlan_rem_error;
158	}
159
160	ret = 0;
161
162vlan_rem_error:
163	if (rlink)
164		rtnl_link_put(rlink);
165	if (handle)
166		nl_socket_free(handle);
167	return ret;
168}
169
170
171int vlan_set_name_type(unsigned int name_type)
172{
173	return 0;
174}
175