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