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