xref: /freebsd/contrib/wpa/src/ap/vlan_init.c (revision c1d255d3)
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