1324714Scy/*
2324714Scy * hostapd / VLAN ioctl API
3324714Scy * Copyright 2003, Instant802 Networks, Inc.
4324714Scy * Copyright 2005-2006, Devicescape Software, Inc.
5324714Scy * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6324714Scy *
7324714Scy * This software may be distributed under the terms of the BSD license.
8324714Scy * See README for more details.
9324714Scy */
10324714Scy
11324714Scy#include "utils/includes.h"
12324714Scy#include <sys/ioctl.h>
13324714Scy
14324714Scy#include "utils/common.h"
15324714Scy#include "common/linux_vlan.h"
16324714Scy#include "vlan_util.h"
17324714Scy
18324714Scy
19324714Scyint vlan_rem(const char *if_name)
20324714Scy{
21324714Scy	int fd;
22324714Scy	struct vlan_ioctl_args if_request;
23324714Scy
24324714Scy	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
25324714Scy	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
26324714Scy		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
27324714Scy			   if_name);
28324714Scy		return -1;
29324714Scy	}
30324714Scy
31324714Scy	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
32324714Scy		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
33324714Scy			   "failed: %s", __func__, strerror(errno));
34324714Scy		return -1;
35324714Scy	}
36324714Scy
37324714Scy	os_memset(&if_request, 0, sizeof(if_request));
38324714Scy
39324714Scy	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
40324714Scy	if_request.cmd = DEL_VLAN_CMD;
41324714Scy
42324714Scy	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
43324714Scy		wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
44324714Scy			   "%s", __func__, if_name, strerror(errno));
45324714Scy		close(fd);
46324714Scy		return -1;
47324714Scy	}
48324714Scy
49324714Scy	close(fd);
50324714Scy	return 0;
51324714Scy}
52324714Scy
53324714Scy
54324714Scy/*
55324714Scy	Add a vlan interface with VLAN ID 'vid' and tagged interface
56324714Scy	'if_name'.
57324714Scy
58324714Scy	returns -1 on error
59324714Scy	returns 1 if the interface already exists
60324714Scy	returns 0 otherwise
61324714Scy*/
62324714Scyint vlan_add(const char *if_name, int vid, const char *vlan_if_name)
63324714Scy{
64324714Scy	int fd;
65324714Scy	struct vlan_ioctl_args if_request;
66324714Scy
67324714Scy	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
68324714Scy		   if_name, vid);
69324714Scy	ifconfig_up(if_name);
70324714Scy
71324714Scy	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
72324714Scy		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
73324714Scy			   if_name);
74324714Scy		return -1;
75324714Scy	}
76324714Scy
77324714Scy	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
78324714Scy		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
79324714Scy			   "failed: %s", __func__, strerror(errno));
80324714Scy		return -1;
81324714Scy	}
82324714Scy
83324714Scy	os_memset(&if_request, 0, sizeof(if_request));
84324714Scy
85324714Scy	/* Determine if a suitable vlan device already exists. */
86324714Scy
87324714Scy	os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
88324714Scy		    vid);
89324714Scy
90324714Scy	if_request.cmd = GET_VLAN_VID_CMD;
91324714Scy
92324714Scy	if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
93324714Scy	    if_request.u.VID == vid) {
94324714Scy		if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
95324714Scy
96324714Scy		if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
97324714Scy		    os_strncmp(if_request.u.device2, if_name,
98324714Scy			       sizeof(if_request.u.device2)) == 0) {
99324714Scy			close(fd);
100324714Scy			wpa_printf(MSG_DEBUG,
101324714Scy				   "VLAN: vlan_add: if_name %s exists already",
102324714Scy				   if_request.device1);
103324714Scy			return 1;
104324714Scy		}
105324714Scy	}
106324714Scy
107324714Scy	/* A suitable vlan device does not already exist, add one. */
108324714Scy
109324714Scy	os_memset(&if_request, 0, sizeof(if_request));
110324714Scy	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
111324714Scy	if_request.u.VID = vid;
112324714Scy	if_request.cmd = ADD_VLAN_CMD;
113324714Scy
114324714Scy	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
115324714Scy		wpa_printf(MSG_ERROR,
116324714Scy			   "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
117324714Scy			   __func__, if_request.device1, strerror(errno));
118324714Scy		close(fd);
119324714Scy		return -1;
120324714Scy	}
121324714Scy
122324714Scy	close(fd);
123324714Scy	return 0;
124324714Scy}
125324714Scy
126324714Scy
127324714Scyint vlan_set_name_type(unsigned int name_type)
128324714Scy{
129324714Scy	int fd;
130324714Scy	struct vlan_ioctl_args if_request;
131324714Scy
132324714Scy	wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
133324714Scy		   name_type);
134324714Scy	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
135324714Scy		wpa_printf(MSG_ERROR,
136324714Scy			   "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
137324714Scy			   __func__, strerror(errno));
138324714Scy		return -1;
139324714Scy	}
140324714Scy
141324714Scy	os_memset(&if_request, 0, sizeof(if_request));
142324714Scy
143324714Scy	if_request.u.name_type = name_type;
144324714Scy	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
145324714Scy	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
146324714Scy		wpa_printf(MSG_ERROR,
147324714Scy			   "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
148324714Scy			   __func__, name_type, strerror(errno));
149324714Scy		close(fd);
150324714Scy		return -1;
151324714Scy	}
152324714Scy
153324714Scy	close(fd);
154324714Scy	return 0;
155324714Scy}
156