xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/vlan_init.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / VLAN initialization
33ff40c12SJohn Marino  * Copyright 2003, Instant802 Networks, Inc.
43ff40c12SJohn Marino  * Copyright 2005-2006, Devicescape Software, Inc.
53ff40c12SJohn Marino  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
63ff40c12SJohn Marino  *
73ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
83ff40c12SJohn Marino  * See README for more details.
93ff40c12SJohn Marino  */
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "utils/includes.h"
123ff40c12SJohn Marino 
133ff40c12SJohn Marino #include "utils/common.h"
143ff40c12SJohn Marino #include "hostapd.h"
153ff40c12SJohn Marino #include "ap_config.h"
163ff40c12SJohn Marino #include "ap_drv_ops.h"
17*a1157835SDaniel Fojt #include "wpa_auth.h"
183ff40c12SJohn Marino #include "vlan_init.h"
193ff40c12SJohn Marino #include "vlan_util.h"
203ff40c12SJohn Marino 
213ff40c12SJohn Marino 
vlan_if_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int existsok)22*a1157835SDaniel Fojt static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23*a1157835SDaniel Fojt 		       int existsok)
243ff40c12SJohn Marino {
25*a1157835SDaniel Fojt 	int ret, i;
263ff40c12SJohn Marino 
27*a1157835SDaniel Fojt 	for (i = 0; i < NUM_WEP_KEYS; i++) {
28*a1157835SDaniel Fojt 		if (!hapd->conf->ssid.wep.key[i])
29*a1157835SDaniel Fojt 			continue;
30*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
31*a1157835SDaniel Fojt 			   "VLAN: Refusing to set up VLAN iface %s with WEP",
32*a1157835SDaniel Fojt 			   vlan->ifname);
333ff40c12SJohn Marino 		return -1;
343ff40c12SJohn Marino 	}
353ff40c12SJohn Marino 
36*a1157835SDaniel Fojt 	if (!iface_exists(vlan->ifname))
37*a1157835SDaniel Fojt 		ret = hostapd_vlan_if_add(hapd, vlan->ifname);
38*a1157835SDaniel Fojt 	else if (!existsok)
393ff40c12SJohn Marino 		return -1;
403ff40c12SJohn Marino 	else
41*a1157835SDaniel Fojt 		ret = 0;
423ff40c12SJohn Marino 
43*a1157835SDaniel Fojt 	if (ret)
44*a1157835SDaniel Fojt 		return ret;
453ff40c12SJohn Marino 
46*a1157835SDaniel Fojt 	ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
47*a1157835SDaniel Fojt 
48*a1157835SDaniel Fojt 	if (hapd->wpa_auth)
49*a1157835SDaniel Fojt 		ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
50*a1157835SDaniel Fojt 
51*a1157835SDaniel Fojt 	if (ret == 0)
52*a1157835SDaniel Fojt 		return ret;
53*a1157835SDaniel Fojt 
54*a1157835SDaniel Fojt 	wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
55*a1157835SDaniel Fojt 		   vlan->vlan_id, ret);
56*a1157835SDaniel Fojt 	if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
57*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
58*a1157835SDaniel Fojt 
59*a1157835SDaniel Fojt 	/* group state machine setup failed */
60*a1157835SDaniel Fojt 	if (hostapd_vlan_if_remove(hapd, vlan->ifname))
61*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
62*a1157835SDaniel Fojt 
63*a1157835SDaniel Fojt 	return ret;
643ff40c12SJohn Marino }
653ff40c12SJohn Marino 
663ff40c12SJohn Marino 
vlan_if_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)67*a1157835SDaniel Fojt int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
683ff40c12SJohn Marino {
693ff40c12SJohn Marino 	int ret;
703ff40c12SJohn Marino 
71*a1157835SDaniel Fojt 	ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
72*a1157835SDaniel Fojt 	if (ret)
73*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
74*a1157835SDaniel Fojt 			   "WPA deinitialization for VLAN %d failed (%d)",
75*a1157835SDaniel Fojt 			   vlan->vlan_id, ret);
763ff40c12SJohn Marino 
77*a1157835SDaniel Fojt 	return hostapd_vlan_if_remove(hapd, vlan->ifname);
783ff40c12SJohn Marino }
793ff40c12SJohn Marino 
803ff40c12SJohn Marino 
vlan_dynamic_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan)813ff40c12SJohn Marino static int vlan_dynamic_add(struct hostapd_data *hapd,
823ff40c12SJohn Marino 			    struct hostapd_vlan *vlan)
833ff40c12SJohn Marino {
843ff40c12SJohn Marino 	while (vlan) {
853ff40c12SJohn Marino 		if (vlan->vlan_id != VLAN_ID_WILDCARD) {
86*a1157835SDaniel Fojt 			if (vlan_if_add(hapd, vlan, 1)) {
87*a1157835SDaniel Fojt 				wpa_printf(MSG_ERROR,
88*a1157835SDaniel Fojt 					   "VLAN: Could not add VLAN %s: %s",
89*a1157835SDaniel Fojt 					   vlan->ifname, strerror(errno));
903ff40c12SJohn Marino 				return -1;
913ff40c12SJohn Marino 			}
923ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
93*a1157835SDaniel Fojt 			vlan_newlink(vlan->ifname, hapd);
943ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
953ff40c12SJohn Marino 		}
963ff40c12SJohn Marino 
973ff40c12SJohn Marino 		vlan = vlan->next;
983ff40c12SJohn Marino 	}
993ff40c12SJohn Marino 
1003ff40c12SJohn Marino 	return 0;
1013ff40c12SJohn Marino }
1023ff40c12SJohn Marino 
1033ff40c12SJohn Marino 
vlan_dynamic_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)1043ff40c12SJohn Marino static void vlan_dynamic_remove(struct hostapd_data *hapd,
1053ff40c12SJohn Marino 				struct hostapd_vlan *vlan)
1063ff40c12SJohn Marino {
1073ff40c12SJohn Marino 	struct hostapd_vlan *next;
1083ff40c12SJohn Marino 
1093ff40c12SJohn Marino 	while (vlan) {
1103ff40c12SJohn Marino 		next = vlan->next;
1113ff40c12SJohn Marino 
112*a1157835SDaniel Fojt #ifdef CONFIG_FULL_DYNAMIC_VLAN
113*a1157835SDaniel Fojt 		/* vlan_dellink() takes care of cleanup and interface removal */
114*a1157835SDaniel Fojt 		if (vlan->vlan_id != VLAN_ID_WILDCARD)
115*a1157835SDaniel Fojt 			vlan_dellink(vlan->ifname, hapd);
116*a1157835SDaniel Fojt #else /* CONFIG_FULL_DYNAMIC_VLAN */
1173ff40c12SJohn Marino 		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
118*a1157835SDaniel Fojt 		    vlan_if_remove(hapd, vlan)) {
1193ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
1203ff40c12SJohn Marino 				   "iface: %s: %s",
1213ff40c12SJohn Marino 				   vlan->ifname, strerror(errno));
1223ff40c12SJohn Marino 		}
1233ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1243ff40c12SJohn Marino 
1253ff40c12SJohn Marino 		vlan = next;
1263ff40c12SJohn Marino 	}
1273ff40c12SJohn Marino }
1283ff40c12SJohn Marino 
1293ff40c12SJohn Marino 
vlan_init(struct hostapd_data * hapd)1303ff40c12SJohn Marino int vlan_init(struct hostapd_data *hapd)
1313ff40c12SJohn Marino {
1323ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
1333ff40c12SJohn Marino 	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
1343ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1353ff40c12SJohn Marino 
136*a1157835SDaniel Fojt 	if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
137*a1157835SDaniel Fojt 	     hapd->conf->ssid.per_sta_vif) &&
1383ff40c12SJohn Marino 	    !hapd->conf->vlan) {
1393ff40c12SJohn Marino 		/* dynamic vlans enabled but no (or empty) vlan_file given */
1403ff40c12SJohn Marino 		struct hostapd_vlan *vlan;
141*a1157835SDaniel Fojt 		int ret;
142*a1157835SDaniel Fojt 
1433ff40c12SJohn Marino 		vlan = os_zalloc(sizeof(*vlan));
1443ff40c12SJohn Marino 		if (vlan == NULL) {
1453ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Out of memory while assigning "
1463ff40c12SJohn Marino 				   "VLAN interfaces");
1473ff40c12SJohn Marino 			return -1;
1483ff40c12SJohn Marino 		}
1493ff40c12SJohn Marino 
1503ff40c12SJohn Marino 		vlan->vlan_id = VLAN_ID_WILDCARD;
151*a1157835SDaniel Fojt 		ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
1523ff40c12SJohn Marino 				  hapd->conf->iface);
153*a1157835SDaniel Fojt 		if (ret >= (int) sizeof(vlan->ifname)) {
154*a1157835SDaniel Fojt 			wpa_printf(MSG_WARNING,
155*a1157835SDaniel Fojt 				   "VLAN: Interface name was truncated to %s",
156*a1157835SDaniel Fojt 				   vlan->ifname);
157*a1157835SDaniel Fojt 		} else if (ret < 0) {
158*a1157835SDaniel Fojt 			os_free(vlan);
159*a1157835SDaniel Fojt 			return ret;
160*a1157835SDaniel Fojt 		}
1613ff40c12SJohn Marino 		vlan->next = hapd->conf->vlan;
1623ff40c12SJohn Marino 		hapd->conf->vlan = vlan;
1633ff40c12SJohn Marino 	}
1643ff40c12SJohn Marino 
1653ff40c12SJohn Marino 	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
1663ff40c12SJohn Marino 		return -1;
1673ff40c12SJohn Marino 
1683ff40c12SJohn Marino         return 0;
1693ff40c12SJohn Marino }
1703ff40c12SJohn Marino 
1713ff40c12SJohn Marino 
vlan_deinit(struct hostapd_data * hapd)1723ff40c12SJohn Marino void vlan_deinit(struct hostapd_data *hapd)
1733ff40c12SJohn Marino {
1743ff40c12SJohn Marino 	vlan_dynamic_remove(hapd, hapd->conf->vlan);
1753ff40c12SJohn Marino 
1763ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
1773ff40c12SJohn Marino 	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
1783ff40c12SJohn Marino 	hapd->full_dynamic_vlan = NULL;
1793ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1803ff40c12SJohn Marino }
1813ff40c12SJohn Marino 
1823ff40c12SJohn Marino 
vlan_add_dynamic(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vlan_id,struct vlan_description * vlan_desc)1833ff40c12SJohn Marino struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
1843ff40c12SJohn Marino 				       struct hostapd_vlan *vlan,
185*a1157835SDaniel Fojt 				       int vlan_id,
186*a1157835SDaniel Fojt 				       struct vlan_description *vlan_desc)
1873ff40c12SJohn Marino {
1883ff40c12SJohn Marino 	struct hostapd_vlan *n;
189*a1157835SDaniel Fojt 	char ifname[IFNAMSIZ + 1], *pos;
190*a1157835SDaniel Fojt 	int ret;
1913ff40c12SJohn Marino 
192*a1157835SDaniel Fojt 	if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
1933ff40c12SJohn Marino 		return NULL;
1943ff40c12SJohn Marino 
1953ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
1963ff40c12SJohn Marino 		   __func__, vlan_id, vlan->ifname);
197*a1157835SDaniel Fojt 	os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
1983ff40c12SJohn Marino 	pos = os_strchr(ifname, '#');
199*a1157835SDaniel Fojt 	if (pos == NULL)
2003ff40c12SJohn Marino 		return NULL;
2013ff40c12SJohn Marino 	*pos++ = '\0';
2023ff40c12SJohn Marino 
2033ff40c12SJohn Marino 	n = os_zalloc(sizeof(*n));
204*a1157835SDaniel Fojt 	if (n == NULL)
2053ff40c12SJohn Marino 		return NULL;
2063ff40c12SJohn Marino 
2073ff40c12SJohn Marino 	n->vlan_id = vlan_id;
208*a1157835SDaniel Fojt 	if (vlan_desc)
209*a1157835SDaniel Fojt 		n->vlan_desc = *vlan_desc;
2103ff40c12SJohn Marino 	n->dynamic_vlan = 1;
2113ff40c12SJohn Marino 
212*a1157835SDaniel Fojt 	ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
213*a1157835SDaniel Fojt 			  ifname, vlan_id, pos);
214*a1157835SDaniel Fojt 	if (os_snprintf_error(sizeof(n->ifname), ret)) {
2153ff40c12SJohn Marino 		os_free(n);
2163ff40c12SJohn Marino 		return NULL;
2173ff40c12SJohn Marino 	}
218*a1157835SDaniel Fojt 	os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
2193ff40c12SJohn Marino 
2203ff40c12SJohn Marino 	n->next = hapd->conf->vlan;
2213ff40c12SJohn Marino 	hapd->conf->vlan = n;
2223ff40c12SJohn Marino 
223*a1157835SDaniel Fojt 	/* hapd->conf->vlan needs this new VLAN here for WPA setup */
224*a1157835SDaniel Fojt 	if (vlan_if_add(hapd, n, 0)) {
225*a1157835SDaniel Fojt 		hapd->conf->vlan = n->next;
226*a1157835SDaniel Fojt 		os_free(n);
227*a1157835SDaniel Fojt 		n = NULL;
228*a1157835SDaniel Fojt 	}
2293ff40c12SJohn Marino 
2303ff40c12SJohn Marino 	return n;
2313ff40c12SJohn Marino }
2323ff40c12SJohn Marino 
2333ff40c12SJohn Marino 
vlan_remove_dynamic(struct hostapd_data * hapd,int vlan_id)2343ff40c12SJohn Marino int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
2353ff40c12SJohn Marino {
2363ff40c12SJohn Marino 	struct hostapd_vlan *vlan;
2373ff40c12SJohn Marino 
238*a1157835SDaniel Fojt 	if (vlan_id <= 0)
2393ff40c12SJohn Marino 		return 1;
2403ff40c12SJohn Marino 
241*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
242*a1157835SDaniel Fojt 		   __func__, hapd->conf->iface, vlan_id);
2433ff40c12SJohn Marino 
2443ff40c12SJohn Marino 	vlan = hapd->conf->vlan;
2453ff40c12SJohn Marino 	while (vlan) {
2463ff40c12SJohn Marino 		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
2473ff40c12SJohn Marino 			vlan->dynamic_vlan--;
2483ff40c12SJohn Marino 			break;
2493ff40c12SJohn Marino 		}
2503ff40c12SJohn Marino 		vlan = vlan->next;
2513ff40c12SJohn Marino 	}
2523ff40c12SJohn Marino 
2533ff40c12SJohn Marino 	if (vlan == NULL)
2543ff40c12SJohn Marino 		return 1;
2553ff40c12SJohn Marino 
256*a1157835SDaniel Fojt 	if (vlan->dynamic_vlan == 0) {
257*a1157835SDaniel Fojt 		vlan_if_remove(hapd, vlan);
258*a1157835SDaniel Fojt #ifdef CONFIG_FULL_DYNAMIC_VLAN
259*a1157835SDaniel Fojt 		vlan_dellink(vlan->ifname, hapd);
260*a1157835SDaniel Fojt #endif /* CONFIG_FULL_DYNAMIC_VLAN */
261*a1157835SDaniel Fojt 	}
2623ff40c12SJohn Marino 
2633ff40c12SJohn Marino 	return 0;
2643ff40c12SJohn Marino }
265