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
19int 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*/
62int 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
127int 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