1e28a4053SRui Paulo /*
2e28a4053SRui Paulo * hostapd / VLAN initialization
3e28a4053SRui Paulo * Copyright 2003, Instant802 Networks, Inc.
4e28a4053SRui Paulo * Copyright 2005-2006, Devicescape Software, Inc.
5e28a4053SRui Paulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6e28a4053SRui Paulo *
75b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
85b9c547cSRui Paulo * See README for more details.
9e28a4053SRui Paulo */
10e28a4053SRui Paulo
11e28a4053SRui Paulo #include "utils/includes.h"
12e28a4053SRui Paulo
13e28a4053SRui Paulo #include "utils/common.h"
14e28a4053SRui Paulo #include "hostapd.h"
15e28a4053SRui Paulo #include "ap_config.h"
16f05cddf9SRui Paulo #include "ap_drv_ops.h"
17780fb4a2SCy Schubert #include "wpa_auth.h"
18e28a4053SRui Paulo #include "vlan_init.h"
19f05cddf9SRui Paulo #include "vlan_util.h"
20e28a4053SRui Paulo
21e28a4053SRui Paulo
vlan_if_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int existsok)22780fb4a2SCy Schubert static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23780fb4a2SCy Schubert int existsok)
24325151a3SRui Paulo {
25*c1d255d3SCy Schubert int ret;
26*c1d255d3SCy Schubert #ifdef CONFIG_WEP
27*c1d255d3SCy Schubert int i;
28325151a3SRui Paulo
29780fb4a2SCy Schubert for (i = 0; i < NUM_WEP_KEYS; i++) {
30780fb4a2SCy Schubert if (!hapd->conf->ssid.wep.key[i])
31780fb4a2SCy Schubert continue;
32780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
33780fb4a2SCy Schubert "VLAN: Refusing to set up VLAN iface %s with WEP",
34780fb4a2SCy Schubert vlan->ifname);
35780fb4a2SCy Schubert return -1;
36325151a3SRui Paulo }
37*c1d255d3SCy Schubert #endif /* CONFIG_WEP */
38325151a3SRui Paulo
39780fb4a2SCy Schubert if (!iface_exists(vlan->ifname))
40780fb4a2SCy Schubert ret = hostapd_vlan_if_add(hapd, vlan->ifname);
41780fb4a2SCy Schubert else if (!existsok)
42780fb4a2SCy Schubert return -1;
43325151a3SRui Paulo else
44780fb4a2SCy Schubert ret = 0;
45325151a3SRui Paulo
46780fb4a2SCy Schubert if (ret)
47780fb4a2SCy Schubert return ret;
48780fb4a2SCy Schubert
49780fb4a2SCy Schubert ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
50780fb4a2SCy Schubert
51780fb4a2SCy Schubert if (hapd->wpa_auth)
52780fb4a2SCy Schubert ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
53780fb4a2SCy Schubert
54780fb4a2SCy Schubert if (ret == 0)
55780fb4a2SCy Schubert return ret;
56780fb4a2SCy Schubert
57780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
58780fb4a2SCy Schubert vlan->vlan_id, ret);
59780fb4a2SCy Schubert if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
60780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
61780fb4a2SCy Schubert
62780fb4a2SCy Schubert /* group state machine setup failed */
63780fb4a2SCy Schubert if (hostapd_vlan_if_remove(hapd, vlan->ifname))
64780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
65780fb4a2SCy Schubert
66780fb4a2SCy Schubert return ret;
67325151a3SRui Paulo }
68325151a3SRui Paulo
69e28a4053SRui Paulo
vlan_if_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)70780fb4a2SCy Schubert int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
71e28a4053SRui Paulo {
72780fb4a2SCy Schubert int ret;
73e28a4053SRui Paulo
74780fb4a2SCy Schubert ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
75780fb4a2SCy Schubert if (ret)
76780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
77780fb4a2SCy Schubert "WPA deinitialization for VLAN %d failed (%d)",
78780fb4a2SCy Schubert vlan->vlan_id, ret);
79e28a4053SRui Paulo
80780fb4a2SCy Schubert return hostapd_vlan_if_remove(hapd, vlan->ifname);
81e28a4053SRui Paulo }
82e28a4053SRui Paulo
83e28a4053SRui Paulo
vlan_dynamic_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan)84e28a4053SRui Paulo static int vlan_dynamic_add(struct hostapd_data *hapd,
85e28a4053SRui Paulo struct hostapd_vlan *vlan)
86e28a4053SRui Paulo {
87e28a4053SRui Paulo while (vlan) {
88e28a4053SRui Paulo if (vlan->vlan_id != VLAN_ID_WILDCARD) {
89780fb4a2SCy Schubert if (vlan_if_add(hapd, vlan, 1)) {
90780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
91780fb4a2SCy Schubert "VLAN: Could not add VLAN %s: %s",
92780fb4a2SCy Schubert vlan->ifname, strerror(errno));
93e28a4053SRui Paulo return -1;
94e28a4053SRui Paulo }
95e28a4053SRui Paulo #ifdef CONFIG_FULL_DYNAMIC_VLAN
96780fb4a2SCy Schubert vlan_newlink(vlan->ifname, hapd);
97e28a4053SRui Paulo #endif /* CONFIG_FULL_DYNAMIC_VLAN */
98e28a4053SRui Paulo }
99e28a4053SRui Paulo
100e28a4053SRui Paulo vlan = vlan->next;
101e28a4053SRui Paulo }
102e28a4053SRui Paulo
103e28a4053SRui Paulo return 0;
104e28a4053SRui Paulo }
105e28a4053SRui Paulo
106e28a4053SRui Paulo
vlan_dynamic_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)107e28a4053SRui Paulo static void vlan_dynamic_remove(struct hostapd_data *hapd,
108e28a4053SRui Paulo struct hostapd_vlan *vlan)
109e28a4053SRui Paulo {
110e28a4053SRui Paulo struct hostapd_vlan *next;
111e28a4053SRui Paulo
112e28a4053SRui Paulo while (vlan) {
113e28a4053SRui Paulo next = vlan->next;
114e28a4053SRui Paulo
115780fb4a2SCy Schubert #ifdef CONFIG_FULL_DYNAMIC_VLAN
116780fb4a2SCy Schubert /* vlan_dellink() takes care of cleanup and interface removal */
117780fb4a2SCy Schubert if (vlan->vlan_id != VLAN_ID_WILDCARD)
118780fb4a2SCy Schubert vlan_dellink(vlan->ifname, hapd);
119780fb4a2SCy Schubert #else /* CONFIG_FULL_DYNAMIC_VLAN */
120e28a4053SRui Paulo if (vlan->vlan_id != VLAN_ID_WILDCARD &&
121780fb4a2SCy Schubert vlan_if_remove(hapd, vlan)) {
122e28a4053SRui Paulo wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
123e28a4053SRui Paulo "iface: %s: %s",
124e28a4053SRui Paulo vlan->ifname, strerror(errno));
125e28a4053SRui Paulo }
126e28a4053SRui Paulo #endif /* CONFIG_FULL_DYNAMIC_VLAN */
127e28a4053SRui Paulo
128e28a4053SRui Paulo vlan = next;
129e28a4053SRui Paulo }
130e28a4053SRui Paulo }
131e28a4053SRui Paulo
132e28a4053SRui Paulo
vlan_init(struct hostapd_data * hapd)133e28a4053SRui Paulo int vlan_init(struct hostapd_data *hapd)
134e28a4053SRui Paulo {
135e28a4053SRui Paulo #ifdef CONFIG_FULL_DYNAMIC_VLAN
136e28a4053SRui Paulo hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
137e28a4053SRui Paulo #endif /* CONFIG_FULL_DYNAMIC_VLAN */
138e28a4053SRui Paulo
139780fb4a2SCy Schubert if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
140780fb4a2SCy Schubert hapd->conf->ssid.per_sta_vif) &&
1415b9c547cSRui Paulo !hapd->conf->vlan) {
1425b9c547cSRui Paulo /* dynamic vlans enabled but no (or empty) vlan_file given */
1435b9c547cSRui Paulo struct hostapd_vlan *vlan;
14485732ac8SCy Schubert int ret;
14585732ac8SCy Schubert
1465b9c547cSRui Paulo vlan = os_zalloc(sizeof(*vlan));
1475b9c547cSRui Paulo if (vlan == NULL) {
1485b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Out of memory while assigning "
1495b9c547cSRui Paulo "VLAN interfaces");
1505b9c547cSRui Paulo return -1;
1515b9c547cSRui Paulo }
1525b9c547cSRui Paulo
1535b9c547cSRui Paulo vlan->vlan_id = VLAN_ID_WILDCARD;
15485732ac8SCy Schubert ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
1555b9c547cSRui Paulo hapd->conf->iface);
15685732ac8SCy Schubert if (ret >= (int) sizeof(vlan->ifname)) {
15785732ac8SCy Schubert wpa_printf(MSG_WARNING,
15885732ac8SCy Schubert "VLAN: Interface name was truncated to %s",
15985732ac8SCy Schubert vlan->ifname);
16085732ac8SCy Schubert } else if (ret < 0) {
16185732ac8SCy Schubert os_free(vlan);
16285732ac8SCy Schubert return ret;
16385732ac8SCy Schubert }
1645b9c547cSRui Paulo vlan->next = hapd->conf->vlan;
1655b9c547cSRui Paulo hapd->conf->vlan = vlan;
1665b9c547cSRui Paulo }
1675b9c547cSRui Paulo
168e28a4053SRui Paulo if (vlan_dynamic_add(hapd, hapd->conf->vlan))
169e28a4053SRui Paulo return -1;
170e28a4053SRui Paulo
171e28a4053SRui Paulo return 0;
172e28a4053SRui Paulo }
173e28a4053SRui Paulo
174e28a4053SRui Paulo
vlan_deinit(struct hostapd_data * hapd)175e28a4053SRui Paulo void vlan_deinit(struct hostapd_data *hapd)
176e28a4053SRui Paulo {
177e28a4053SRui Paulo vlan_dynamic_remove(hapd, hapd->conf->vlan);
178e28a4053SRui Paulo
179e28a4053SRui Paulo #ifdef CONFIG_FULL_DYNAMIC_VLAN
180e28a4053SRui Paulo full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
1815b9c547cSRui Paulo hapd->full_dynamic_vlan = NULL;
182e28a4053SRui Paulo #endif /* CONFIG_FULL_DYNAMIC_VLAN */
183e28a4053SRui Paulo }
184e28a4053SRui Paulo
185e28a4053SRui Paulo
vlan_add_dynamic(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vlan_id,struct vlan_description * vlan_desc)186e28a4053SRui Paulo struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
187e28a4053SRui Paulo struct hostapd_vlan *vlan,
188780fb4a2SCy Schubert int vlan_id,
189780fb4a2SCy Schubert struct vlan_description *vlan_desc)
190e28a4053SRui Paulo {
191780fb4a2SCy Schubert struct hostapd_vlan *n;
192780fb4a2SCy Schubert char ifname[IFNAMSIZ + 1], *pos;
1934bc52338SCy Schubert int ret;
194e28a4053SRui Paulo
195780fb4a2SCy Schubert if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
196e28a4053SRui Paulo return NULL;
197e28a4053SRui Paulo
198e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
199e28a4053SRui Paulo __func__, vlan_id, vlan->ifname);
200780fb4a2SCy Schubert os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
201e28a4053SRui Paulo pos = os_strchr(ifname, '#');
2025b9c547cSRui Paulo if (pos == NULL)
203780fb4a2SCy Schubert return NULL;
204e28a4053SRui Paulo *pos++ = '\0';
205e28a4053SRui Paulo
206e28a4053SRui Paulo n = os_zalloc(sizeof(*n));
2075b9c547cSRui Paulo if (n == NULL)
208780fb4a2SCy Schubert return NULL;
209e28a4053SRui Paulo
210e28a4053SRui Paulo n->vlan_id = vlan_id;
211780fb4a2SCy Schubert if (vlan_desc)
212780fb4a2SCy Schubert n->vlan_desc = *vlan_desc;
213e28a4053SRui Paulo n->dynamic_vlan = 1;
214e28a4053SRui Paulo
2154bc52338SCy Schubert ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
2164bc52338SCy Schubert ifname, vlan_id, pos);
2174bc52338SCy Schubert if (os_snprintf_error(sizeof(n->ifname), ret)) {
2184bc52338SCy Schubert os_free(n);
2194bc52338SCy Schubert return NULL;
2204bc52338SCy Schubert }
2214bc52338SCy Schubert os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
222e28a4053SRui Paulo
223e28a4053SRui Paulo n->next = hapd->conf->vlan;
224e28a4053SRui Paulo hapd->conf->vlan = n;
225e28a4053SRui Paulo
226780fb4a2SCy Schubert /* hapd->conf->vlan needs this new VLAN here for WPA setup */
227780fb4a2SCy Schubert if (vlan_if_add(hapd, n, 0)) {
228780fb4a2SCy Schubert hapd->conf->vlan = n->next;
229780fb4a2SCy Schubert os_free(n);
230780fb4a2SCy Schubert n = NULL;
231780fb4a2SCy Schubert }
232e28a4053SRui Paulo
233e28a4053SRui Paulo return n;
234e28a4053SRui Paulo }
235e28a4053SRui Paulo
236e28a4053SRui Paulo
vlan_remove_dynamic(struct hostapd_data * hapd,int vlan_id)237e28a4053SRui Paulo int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
238e28a4053SRui Paulo {
239e28a4053SRui Paulo struct hostapd_vlan *vlan;
240e28a4053SRui Paulo
241780fb4a2SCy Schubert if (vlan_id <= 0)
242e28a4053SRui Paulo return 1;
243e28a4053SRui Paulo
244325151a3SRui Paulo wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
245325151a3SRui Paulo __func__, hapd->conf->iface, vlan_id);
246e28a4053SRui Paulo
247e28a4053SRui Paulo vlan = hapd->conf->vlan;
248e28a4053SRui Paulo while (vlan) {
249e28a4053SRui Paulo if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
250e28a4053SRui Paulo vlan->dynamic_vlan--;
251e28a4053SRui Paulo break;
252e28a4053SRui Paulo }
253e28a4053SRui Paulo vlan = vlan->next;
254e28a4053SRui Paulo }
255e28a4053SRui Paulo
256e28a4053SRui Paulo if (vlan == NULL)
257e28a4053SRui Paulo return 1;
258e28a4053SRui Paulo
259325151a3SRui Paulo if (vlan->dynamic_vlan == 0) {
260780fb4a2SCy Schubert vlan_if_remove(hapd, vlan);
261325151a3SRui Paulo #ifdef CONFIG_FULL_DYNAMIC_VLAN
262325151a3SRui Paulo vlan_dellink(vlan->ifname, hapd);
263325151a3SRui Paulo #endif /* CONFIG_FULL_DYNAMIC_VLAN */
264325151a3SRui Paulo }
265e28a4053SRui Paulo
266e28a4053SRui Paulo return 0;
267e28a4053SRui Paulo }
268