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