161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/*
261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * hostapd / VLAN netlink api
361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *
561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * See README for more details.
761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */
861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/includes.h"
1061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/route/link.h>
1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include <netlink/route/link/vlan.h>
1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/common.h"
1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "vlan_util.h"
1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/*
1761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
1861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * tagged interface 'if_name'.
1961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *
2061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns -1 on error
2161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 1 if the interface already exists
2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * returns 0 otherwise
2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt*/
2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_add(const char *if_name, int vid, const char *vlan_if_name)
2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
2605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	int err, ret = -1;
2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct nl_sock *handle = NULL;
2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct rtnl_link *rlink = NULL;
2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int if_idx = 0;
3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   if_name);
3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   vlan_if_name);
4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
4461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	handle = nl_socket_alloc();
4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!handle) {
4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
5205df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = nl_connect(handle, NETLINK_ROUTE);
5305df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
5405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
5505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   nl_geterror(err));
5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
599c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
6005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* link does not exist */
6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   if_name);
6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
669c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if_idx = rtnl_link_get_ifindex(rlink);
679c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	rtnl_link_put(rlink);
689c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	rlink = NULL;
6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
709c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
719c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	if (err >= 0) {
7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* link does exist */
7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		rtnl_link_put(rlink);
7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		rlink = NULL;
7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   vlan_if_name);
7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		ret = 1;
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	rlink = rtnl_link_alloc();
8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!rlink) {
8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = rtnl_link_set_type(rlink, "vlan");
8805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
8905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
9005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   nl_geterror(err));
9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	rtnl_link_set_link(rlink, if_idx);
9561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	rtnl_link_set_name(rlink, vlan_if_name);
9661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = rtnl_link_vlan_set_id(rlink, vid);
9805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
9905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
10005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   nl_geterror(err));
10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
10405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
10505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
10705df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   "vlan %d on %s (%d): %s",
10805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   vlan_if_name, vid, if_name, if_idx,
10905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   nl_geterror(err));
11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_add_error;
11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ret = 0;
11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_add_error:
11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (rlink)
11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		rtnl_link_put(rlink);
11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (handle)
11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl_socket_free(handle);
12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return ret;
12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint vlan_rem(const char *if_name)
12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
12605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	int err, ret = -1;
12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct nl_sock *handle = NULL;
12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct rtnl_link *rlink = NULL;
12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	handle = nl_socket_alloc();
13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!handle) {
13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_rem_error;
13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
13805df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = nl_connect(handle, NETLINK_ROUTE);
13905df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
14005df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
14105df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   nl_geterror(err));
14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_rem_error;
14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1459c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
14605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* link does not exist */
14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   if_name);
15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_rem_error;
15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
15305df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	err = rtnl_link_delete(handle, rlink);
15405df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt	if (err < 0) {
15505df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
15605df46a3aef489a33f92efb91b091c1aa6d16f95Dmitry Shmidt			   if_name, nl_geterror(err));
15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto vlan_rem_error;
15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ret = 0;
16161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvlan_rem_error:
16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (rlink)
16461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		rtnl_link_put(rlink);
16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (handle)
16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl_socket_free(handle);
16761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return ret;
16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
169e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
170e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
171e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidtint vlan_set_name_type(unsigned int name_type)
172e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt{
173e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	return 0;
174e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt}
175