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 <netlink/route/link.h>
11252190Srpaulo#include <netlink/route/link/vlan.h>
12252190Srpaulo
13252190Srpaulo#include "utils/common.h"
14252190Srpaulo#include "vlan_util.h"
15252190Srpaulo
16252190Srpaulo/*
17252190Srpaulo * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
18252190Srpaulo * tagged interface 'if_name'.
19252190Srpaulo *
20252190Srpaulo * returns -1 on error
21252190Srpaulo * returns 1 if the interface already exists
22252190Srpaulo * returns 0 otherwise
23252190Srpaulo*/
24252190Srpauloint vlan_add(const char *if_name, int vid, const char *vlan_if_name)
25252190Srpaulo{
26289549Srpaulo	int err, ret = -1;
27252190Srpaulo	struct nl_sock *handle = NULL;
28252190Srpaulo	struct rtnl_link *rlink = NULL;
29252190Srpaulo	int if_idx = 0;
30252190Srpaulo
31252190Srpaulo	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
32252190Srpaulo		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
33252190Srpaulo
34252190Srpaulo	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
35252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
36252190Srpaulo			   if_name);
37252190Srpaulo		return -1;
38252190Srpaulo	}
39252190Srpaulo
40252190Srpaulo	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
41252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
42252190Srpaulo			   vlan_if_name);
43252190Srpaulo		return -1;
44252190Srpaulo	}
45252190Srpaulo
46252190Srpaulo	handle = nl_socket_alloc();
47252190Srpaulo	if (!handle) {
48252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
49252190Srpaulo		goto vlan_add_error;
50252190Srpaulo	}
51252190Srpaulo
52289549Srpaulo	err = nl_connect(handle, NETLINK_ROUTE);
53289549Srpaulo	if (err < 0) {
54289549Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
55289549Srpaulo			   nl_geterror(err));
56252190Srpaulo		goto vlan_add_error;
57252190Srpaulo	}
58252190Srpaulo
59337817Scy	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
60289549Srpaulo	if (err < 0) {
61252190Srpaulo		/* link does not exist */
62252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
63252190Srpaulo			   if_name);
64252190Srpaulo		goto vlan_add_error;
65252190Srpaulo	}
66337817Scy	if_idx = rtnl_link_get_ifindex(rlink);
67337817Scy	rtnl_link_put(rlink);
68337817Scy	rlink = NULL;
69252190Srpaulo
70337817Scy	err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
71337817Scy	if (err >= 0) {
72252190Srpaulo		/* link does exist */
73252190Srpaulo		rtnl_link_put(rlink);
74252190Srpaulo		rlink = NULL;
75252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
76252190Srpaulo			   vlan_if_name);
77252190Srpaulo		ret = 1;
78252190Srpaulo		goto vlan_add_error;
79252190Srpaulo	}
80252190Srpaulo
81252190Srpaulo	rlink = rtnl_link_alloc();
82252190Srpaulo	if (!rlink) {
83252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
84252190Srpaulo		goto vlan_add_error;
85252190Srpaulo	}
86252190Srpaulo
87289549Srpaulo	err = rtnl_link_set_type(rlink, "vlan");
88289549Srpaulo	if (err < 0) {
89289549Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
90289549Srpaulo			   nl_geterror(err));
91252190Srpaulo		goto vlan_add_error;
92252190Srpaulo	}
93252190Srpaulo
94252190Srpaulo	rtnl_link_set_link(rlink, if_idx);
95252190Srpaulo	rtnl_link_set_name(rlink, vlan_if_name);
96252190Srpaulo
97289549Srpaulo	err = rtnl_link_vlan_set_id(rlink, vid);
98289549Srpaulo	if (err < 0) {
99289549Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
100289549Srpaulo			   nl_geterror(err));
101252190Srpaulo		goto vlan_add_error;
102252190Srpaulo	}
103252190Srpaulo
104289549Srpaulo	err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
105289549Srpaulo	if (err < 0) {
106252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
107289549Srpaulo			   "vlan %d on %s (%d): %s",
108289549Srpaulo			   vlan_if_name, vid, if_name, if_idx,
109289549Srpaulo			   nl_geterror(err));
110252190Srpaulo		goto vlan_add_error;
111252190Srpaulo	}
112252190Srpaulo
113252190Srpaulo	ret = 0;
114252190Srpaulo
115252190Srpaulovlan_add_error:
116252190Srpaulo	if (rlink)
117252190Srpaulo		rtnl_link_put(rlink);
118252190Srpaulo	if (handle)
119252190Srpaulo		nl_socket_free(handle);
120252190Srpaulo	return ret;
121252190Srpaulo}
122252190Srpaulo
123252190Srpaulo
124252190Srpauloint vlan_rem(const char *if_name)
125252190Srpaulo{
126289549Srpaulo	int err, ret = -1;
127252190Srpaulo	struct nl_sock *handle = NULL;
128252190Srpaulo	struct rtnl_link *rlink = NULL;
129252190Srpaulo
130252190Srpaulo	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
131252190Srpaulo
132252190Srpaulo	handle = nl_socket_alloc();
133252190Srpaulo	if (!handle) {
134252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
135252190Srpaulo		goto vlan_rem_error;
136252190Srpaulo	}
137252190Srpaulo
138289549Srpaulo	err = nl_connect(handle, NETLINK_ROUTE);
139289549Srpaulo	if (err < 0) {
140289549Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
141289549Srpaulo			   nl_geterror(err));
142252190Srpaulo		goto vlan_rem_error;
143252190Srpaulo	}
144252190Srpaulo
145337817Scy	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
146289549Srpaulo	if (err < 0) {
147252190Srpaulo		/* link does not exist */
148252190Srpaulo		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
149252190Srpaulo			   if_name);
150252190Srpaulo		goto vlan_rem_error;
151252190Srpaulo	}
152252190Srpaulo
153289549Srpaulo	err = rtnl_link_delete(handle, rlink);
154289549Srpaulo	if (err < 0) {
155289549Srpaulo		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
156289549Srpaulo			   if_name, nl_geterror(err));
157252190Srpaulo		goto vlan_rem_error;
158252190Srpaulo	}
159252190Srpaulo
160252190Srpaulo	ret = 0;
161252190Srpaulo
162252190Srpaulovlan_rem_error:
163252190Srpaulo	if (rlink)
164252190Srpaulo		rtnl_link_put(rlink);
165252190Srpaulo	if (handle)
166252190Srpaulo		nl_socket_free(handle);
167252190Srpaulo	return ret;
168252190Srpaulo}
169337817Scy
170337817Scy
171337817Scyint vlan_set_name_type(unsigned int name_type)
172337817Scy{
173337817Scy	return 0;
174337817Scy}
175