1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt  * hostapd / VLAN ioctl API
3*a1157835SDaniel Fojt  * Copyright 2003, Instant802 Networks, Inc.
4*a1157835SDaniel Fojt  * Copyright 2005-2006, Devicescape Software, Inc.
5*a1157835SDaniel Fojt  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6*a1157835SDaniel Fojt  *
7*a1157835SDaniel Fojt  * This software may be distributed under the terms of the BSD license.
8*a1157835SDaniel Fojt  * See README for more details.
9*a1157835SDaniel Fojt  */
10*a1157835SDaniel Fojt 
11*a1157835SDaniel Fojt #include "utils/includes.h"
12*a1157835SDaniel Fojt #include <sys/ioctl.h>
13*a1157835SDaniel Fojt 
14*a1157835SDaniel Fojt #include "utils/common.h"
15*a1157835SDaniel Fojt #include "common/linux_vlan.h"
16*a1157835SDaniel Fojt #include "vlan_util.h"
17*a1157835SDaniel Fojt 
18*a1157835SDaniel Fojt 
vlan_rem(const char * if_name)19*a1157835SDaniel Fojt int vlan_rem(const char *if_name)
20*a1157835SDaniel Fojt {
21*a1157835SDaniel Fojt 	int fd;
22*a1157835SDaniel Fojt 	struct vlan_ioctl_args if_request;
23*a1157835SDaniel Fojt 
24*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
25*a1157835SDaniel Fojt 	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
26*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
27*a1157835SDaniel Fojt 			   if_name);
28*a1157835SDaniel Fojt 		return -1;
29*a1157835SDaniel Fojt 	}
30*a1157835SDaniel Fojt 
31*a1157835SDaniel Fojt 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
32*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
33*a1157835SDaniel Fojt 			   "failed: %s", __func__, strerror(errno));
34*a1157835SDaniel Fojt 		return -1;
35*a1157835SDaniel Fojt 	}
36*a1157835SDaniel Fojt 
37*a1157835SDaniel Fojt 	os_memset(&if_request, 0, sizeof(if_request));
38*a1157835SDaniel Fojt 
39*a1157835SDaniel Fojt 	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
40*a1157835SDaniel Fojt 	if_request.cmd = DEL_VLAN_CMD;
41*a1157835SDaniel Fojt 
42*a1157835SDaniel Fojt 	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
43*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
44*a1157835SDaniel Fojt 			   "%s", __func__, if_name, strerror(errno));
45*a1157835SDaniel Fojt 		close(fd);
46*a1157835SDaniel Fojt 		return -1;
47*a1157835SDaniel Fojt 	}
48*a1157835SDaniel Fojt 
49*a1157835SDaniel Fojt 	close(fd);
50*a1157835SDaniel Fojt 	return 0;
51*a1157835SDaniel Fojt }
52*a1157835SDaniel Fojt 
53*a1157835SDaniel Fojt 
54*a1157835SDaniel Fojt /*
55*a1157835SDaniel Fojt 	Add a vlan interface with VLAN ID 'vid' and tagged interface
56*a1157835SDaniel Fojt 	'if_name'.
57*a1157835SDaniel Fojt 
58*a1157835SDaniel Fojt 	returns -1 on error
59*a1157835SDaniel Fojt 	returns 1 if the interface already exists
60*a1157835SDaniel Fojt 	returns 0 otherwise
61*a1157835SDaniel Fojt */
vlan_add(const char * if_name,int vid,const char * vlan_if_name)62*a1157835SDaniel Fojt int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
63*a1157835SDaniel Fojt {
64*a1157835SDaniel Fojt 	int fd;
65*a1157835SDaniel Fojt 	struct vlan_ioctl_args if_request;
66*a1157835SDaniel Fojt 
67*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
68*a1157835SDaniel Fojt 		   if_name, vid);
69*a1157835SDaniel Fojt 	ifconfig_up(if_name);
70*a1157835SDaniel Fojt 
71*a1157835SDaniel Fojt 	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
72*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
73*a1157835SDaniel Fojt 			   if_name);
74*a1157835SDaniel Fojt 		return -1;
75*a1157835SDaniel Fojt 	}
76*a1157835SDaniel Fojt 
77*a1157835SDaniel Fojt 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
78*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
79*a1157835SDaniel Fojt 			   "failed: %s", __func__, strerror(errno));
80*a1157835SDaniel Fojt 		return -1;
81*a1157835SDaniel Fojt 	}
82*a1157835SDaniel Fojt 
83*a1157835SDaniel Fojt 	os_memset(&if_request, 0, sizeof(if_request));
84*a1157835SDaniel Fojt 
85*a1157835SDaniel Fojt 	/* Determine if a suitable vlan device already exists. */
86*a1157835SDaniel Fojt 
87*a1157835SDaniel Fojt 	os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
88*a1157835SDaniel Fojt 		    vid);
89*a1157835SDaniel Fojt 
90*a1157835SDaniel Fojt 	if_request.cmd = GET_VLAN_VID_CMD;
91*a1157835SDaniel Fojt 
92*a1157835SDaniel Fojt 	if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
93*a1157835SDaniel Fojt 	    if_request.u.VID == vid) {
94*a1157835SDaniel Fojt 		if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
95*a1157835SDaniel Fojt 
96*a1157835SDaniel Fojt 		if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
97*a1157835SDaniel Fojt 		    os_strncmp(if_request.u.device2, if_name,
98*a1157835SDaniel Fojt 			       sizeof(if_request.u.device2)) == 0) {
99*a1157835SDaniel Fojt 			close(fd);
100*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
101*a1157835SDaniel Fojt 				   "VLAN: vlan_add: if_name %s exists already",
102*a1157835SDaniel Fojt 				   if_request.device1);
103*a1157835SDaniel Fojt 			return 1;
104*a1157835SDaniel Fojt 		}
105*a1157835SDaniel Fojt 	}
106*a1157835SDaniel Fojt 
107*a1157835SDaniel Fojt 	/* A suitable vlan device does not already exist, add one. */
108*a1157835SDaniel Fojt 
109*a1157835SDaniel Fojt 	os_memset(&if_request, 0, sizeof(if_request));
110*a1157835SDaniel Fojt 	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
111*a1157835SDaniel Fojt 	if_request.u.VID = vid;
112*a1157835SDaniel Fojt 	if_request.cmd = ADD_VLAN_CMD;
113*a1157835SDaniel Fojt 
114*a1157835SDaniel Fojt 	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
115*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
116*a1157835SDaniel Fojt 			   "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
117*a1157835SDaniel Fojt 			   __func__, if_request.device1, strerror(errno));
118*a1157835SDaniel Fojt 		close(fd);
119*a1157835SDaniel Fojt 		return -1;
120*a1157835SDaniel Fojt 	}
121*a1157835SDaniel Fojt 
122*a1157835SDaniel Fojt 	close(fd);
123*a1157835SDaniel Fojt 	return 0;
124*a1157835SDaniel Fojt }
125*a1157835SDaniel Fojt 
126*a1157835SDaniel Fojt 
vlan_set_name_type(unsigned int name_type)127*a1157835SDaniel Fojt int vlan_set_name_type(unsigned int name_type)
128*a1157835SDaniel Fojt {
129*a1157835SDaniel Fojt 	int fd;
130*a1157835SDaniel Fojt 	struct vlan_ioctl_args if_request;
131*a1157835SDaniel Fojt 
132*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
133*a1157835SDaniel Fojt 		   name_type);
134*a1157835SDaniel Fojt 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
135*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
136*a1157835SDaniel Fojt 			   "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
137*a1157835SDaniel Fojt 			   __func__, strerror(errno));
138*a1157835SDaniel Fojt 		return -1;
139*a1157835SDaniel Fojt 	}
140*a1157835SDaniel Fojt 
141*a1157835SDaniel Fojt 	os_memset(&if_request, 0, sizeof(if_request));
142*a1157835SDaniel Fojt 
143*a1157835SDaniel Fojt 	if_request.u.name_type = name_type;
144*a1157835SDaniel Fojt 	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
145*a1157835SDaniel Fojt 	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
146*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
147*a1157835SDaniel Fojt 			   "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
148*a1157835SDaniel Fojt 			   __func__, name_type, strerror(errno));
149*a1157835SDaniel Fojt 		close(fd);
150*a1157835SDaniel Fojt 		return -1;
151*a1157835SDaniel Fojt 	}
152*a1157835SDaniel Fojt 
153*a1157835SDaniel Fojt 	close(fd);
154*a1157835SDaniel Fojt 	return 0;
155*a1157835SDaniel Fojt }
156