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