13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / VLAN netlink api
33ff40c12SJohn Marino  * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "utils/includes.h"
103ff40c12SJohn Marino #include <netlink/route/link.h>
113ff40c12SJohn Marino #include <netlink/route/link/vlan.h>
123ff40c12SJohn Marino 
133ff40c12SJohn Marino #include "utils/common.h"
143ff40c12SJohn Marino #include "vlan_util.h"
153ff40c12SJohn Marino 
163ff40c12SJohn Marino /*
173ff40c12SJohn Marino  * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
183ff40c12SJohn Marino  * tagged interface 'if_name'.
193ff40c12SJohn Marino  *
203ff40c12SJohn Marino  * returns -1 on error
213ff40c12SJohn Marino  * returns 1 if the interface already exists
223ff40c12SJohn Marino  * returns 0 otherwise
233ff40c12SJohn Marino */
vlan_add(const char * if_name,int vid,const char * vlan_if_name)243ff40c12SJohn Marino int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
253ff40c12SJohn Marino {
26*a1157835SDaniel Fojt 	int err, ret = -1;
273ff40c12SJohn Marino 	struct nl_sock *handle = NULL;
283ff40c12SJohn Marino 	struct rtnl_link *rlink = NULL;
293ff40c12SJohn Marino 	int if_idx = 0;
303ff40c12SJohn Marino 
313ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
323ff40c12SJohn Marino 		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
333ff40c12SJohn Marino 
343ff40c12SJohn Marino 	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
353ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
363ff40c12SJohn Marino 			   if_name);
373ff40c12SJohn Marino 		return -1;
383ff40c12SJohn Marino 	}
393ff40c12SJohn Marino 
403ff40c12SJohn Marino 	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
413ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
423ff40c12SJohn Marino 			   vlan_if_name);
433ff40c12SJohn Marino 		return -1;
443ff40c12SJohn Marino 	}
453ff40c12SJohn Marino 
463ff40c12SJohn Marino 	handle = nl_socket_alloc();
473ff40c12SJohn Marino 	if (!handle) {
483ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
493ff40c12SJohn Marino 		goto vlan_add_error;
503ff40c12SJohn Marino 	}
513ff40c12SJohn Marino 
52*a1157835SDaniel Fojt 	err = nl_connect(handle, NETLINK_ROUTE);
53*a1157835SDaniel Fojt 	if (err < 0) {
54*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
55*a1157835SDaniel Fojt 			   nl_geterror(err));
563ff40c12SJohn Marino 		goto vlan_add_error;
573ff40c12SJohn Marino 	}
583ff40c12SJohn Marino 
59*a1157835SDaniel Fojt 	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
60*a1157835SDaniel Fojt 	if (err < 0) {
613ff40c12SJohn Marino 		/* link does not exist */
623ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
633ff40c12SJohn Marino 			   if_name);
643ff40c12SJohn Marino 		goto vlan_add_error;
653ff40c12SJohn Marino 	}
66*a1157835SDaniel Fojt 	if_idx = rtnl_link_get_ifindex(rlink);
67*a1157835SDaniel Fojt 	rtnl_link_put(rlink);
68*a1157835SDaniel Fojt 	rlink = NULL;
693ff40c12SJohn Marino 
70*a1157835SDaniel Fojt 	err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
71*a1157835SDaniel Fojt 	if (err >= 0) {
723ff40c12SJohn Marino 		/* link does exist */
733ff40c12SJohn Marino 		rtnl_link_put(rlink);
743ff40c12SJohn Marino 		rlink = NULL;
753ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
763ff40c12SJohn Marino 			   vlan_if_name);
773ff40c12SJohn Marino 		ret = 1;
783ff40c12SJohn Marino 		goto vlan_add_error;
793ff40c12SJohn Marino 	}
803ff40c12SJohn Marino 
813ff40c12SJohn Marino 	rlink = rtnl_link_alloc();
823ff40c12SJohn Marino 	if (!rlink) {
833ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
843ff40c12SJohn Marino 		goto vlan_add_error;
853ff40c12SJohn Marino 	}
863ff40c12SJohn Marino 
87*a1157835SDaniel Fojt 	err = rtnl_link_set_type(rlink, "vlan");
88*a1157835SDaniel Fojt 	if (err < 0) {
89*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
90*a1157835SDaniel Fojt 			   nl_geterror(err));
913ff40c12SJohn Marino 		goto vlan_add_error;
923ff40c12SJohn Marino 	}
933ff40c12SJohn Marino 
943ff40c12SJohn Marino 	rtnl_link_set_link(rlink, if_idx);
953ff40c12SJohn Marino 	rtnl_link_set_name(rlink, vlan_if_name);
963ff40c12SJohn Marino 
97*a1157835SDaniel Fojt 	err = rtnl_link_vlan_set_id(rlink, vid);
98*a1157835SDaniel Fojt 	if (err < 0) {
99*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
100*a1157835SDaniel Fojt 			   nl_geterror(err));
1013ff40c12SJohn Marino 		goto vlan_add_error;
1023ff40c12SJohn Marino 	}
1033ff40c12SJohn Marino 
104*a1157835SDaniel Fojt 	err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
105*a1157835SDaniel Fojt 	if (err < 0) {
1063ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
107*a1157835SDaniel Fojt 			   "vlan %d on %s (%d): %s",
108*a1157835SDaniel Fojt 			   vlan_if_name, vid, if_name, if_idx,
109*a1157835SDaniel Fojt 			   nl_geterror(err));
1103ff40c12SJohn Marino 		goto vlan_add_error;
1113ff40c12SJohn Marino 	}
1123ff40c12SJohn Marino 
1133ff40c12SJohn Marino 	ret = 0;
1143ff40c12SJohn Marino 
1153ff40c12SJohn Marino vlan_add_error:
1163ff40c12SJohn Marino 	if (rlink)
1173ff40c12SJohn Marino 		rtnl_link_put(rlink);
1183ff40c12SJohn Marino 	if (handle)
1193ff40c12SJohn Marino 		nl_socket_free(handle);
1203ff40c12SJohn Marino 	return ret;
1213ff40c12SJohn Marino }
1223ff40c12SJohn Marino 
1233ff40c12SJohn Marino 
vlan_rem(const char * if_name)1243ff40c12SJohn Marino int vlan_rem(const char *if_name)
1253ff40c12SJohn Marino {
126*a1157835SDaniel Fojt 	int err, ret = -1;
1273ff40c12SJohn Marino 	struct nl_sock *handle = NULL;
1283ff40c12SJohn Marino 	struct rtnl_link *rlink = NULL;
1293ff40c12SJohn Marino 
1303ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
1313ff40c12SJohn Marino 
1323ff40c12SJohn Marino 	handle = nl_socket_alloc();
1333ff40c12SJohn Marino 	if (!handle) {
1343ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
1353ff40c12SJohn Marino 		goto vlan_rem_error;
1363ff40c12SJohn Marino 	}
1373ff40c12SJohn Marino 
138*a1157835SDaniel Fojt 	err = nl_connect(handle, NETLINK_ROUTE);
139*a1157835SDaniel Fojt 	if (err < 0) {
140*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
141*a1157835SDaniel Fojt 			   nl_geterror(err));
1423ff40c12SJohn Marino 		goto vlan_rem_error;
1433ff40c12SJohn Marino 	}
1443ff40c12SJohn Marino 
145*a1157835SDaniel Fojt 	err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
146*a1157835SDaniel Fojt 	if (err < 0) {
1473ff40c12SJohn Marino 		/* link does not exist */
1483ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
1493ff40c12SJohn Marino 			   if_name);
1503ff40c12SJohn Marino 		goto vlan_rem_error;
1513ff40c12SJohn Marino 	}
1523ff40c12SJohn Marino 
153*a1157835SDaniel Fojt 	err = rtnl_link_delete(handle, rlink);
154*a1157835SDaniel Fojt 	if (err < 0) {
155*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
156*a1157835SDaniel Fojt 			   if_name, nl_geterror(err));
1573ff40c12SJohn Marino 		goto vlan_rem_error;
1583ff40c12SJohn Marino 	}
1593ff40c12SJohn Marino 
1603ff40c12SJohn Marino 	ret = 0;
1613ff40c12SJohn Marino 
1623ff40c12SJohn Marino vlan_rem_error:
1633ff40c12SJohn Marino 	if (rlink)
1643ff40c12SJohn Marino 		rtnl_link_put(rlink);
1653ff40c12SJohn Marino 	if (handle)
1663ff40c12SJohn Marino 		nl_socket_free(handle);
1673ff40c12SJohn Marino 	return ret;
1683ff40c12SJohn Marino }
169*a1157835SDaniel Fojt 
170*a1157835SDaniel Fojt 
vlan_set_name_type(unsigned int name_type)171*a1157835SDaniel Fojt int vlan_set_name_type(unsigned int name_type)
172*a1157835SDaniel Fojt {
173*a1157835SDaniel Fojt 	return 0;
174*a1157835SDaniel Fojt }
175