1 /*
2  * hostapd / VLAN initialization
3  * Copyright 2003, Instant802 Networks, Inc.
4  * Copyright 2005-2006, Devicescape Software, Inc.
5  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10 
11 #include "utils/includes.h"
12 
13 #include "utils/common.h"
14 #include "hostapd.h"
15 #include "ap_config.h"
16 #include "ap_drv_ops.h"
17 #include "wpa_auth.h"
18 #include "vlan_init.h"
19 #include "vlan_util.h"
20 
21 
vlan_if_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int existsok)22 static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23 		       int existsok)
24 {
25 	int ret, i;
26 
27 	for (i = 0; i < NUM_WEP_KEYS; i++) {
28 		if (!hapd->conf->ssid.wep.key[i])
29 			continue;
30 		wpa_printf(MSG_ERROR,
31 			   "VLAN: Refusing to set up VLAN iface %s with WEP",
32 			   vlan->ifname);
33 		return -1;
34 	}
35 
36 	if (!iface_exists(vlan->ifname))
37 		ret = hostapd_vlan_if_add(hapd, vlan->ifname);
38 	else if (!existsok)
39 		return -1;
40 	else
41 		ret = 0;
42 
43 	if (ret)
44 		return ret;
45 
46 	ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
47 
48 	if (hapd->wpa_auth)
49 		ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
50 
51 	if (ret == 0)
52 		return ret;
53 
54 	wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
55 		   vlan->vlan_id, ret);
56 	if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
57 		wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
58 
59 	/* group state machine setup failed */
60 	if (hostapd_vlan_if_remove(hapd, vlan->ifname))
61 		wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
62 
63 	return ret;
64 }
65 
66 
vlan_if_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)67 int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
68 {
69 	int ret;
70 
71 	ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
72 	if (ret)
73 		wpa_printf(MSG_ERROR,
74 			   "WPA deinitialization for VLAN %d failed (%d)",
75 			   vlan->vlan_id, ret);
76 
77 	return hostapd_vlan_if_remove(hapd, vlan->ifname);
78 }
79 
80 
vlan_dynamic_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan)81 static int vlan_dynamic_add(struct hostapd_data *hapd,
82 			    struct hostapd_vlan *vlan)
83 {
84 	while (vlan) {
85 		if (vlan->vlan_id != VLAN_ID_WILDCARD) {
86 			if (vlan_if_add(hapd, vlan, 1)) {
87 				wpa_printf(MSG_ERROR,
88 					   "VLAN: Could not add VLAN %s: %s",
89 					   vlan->ifname, strerror(errno));
90 				return -1;
91 			}
92 #ifdef CONFIG_FULL_DYNAMIC_VLAN
93 			vlan_newlink(vlan->ifname, hapd);
94 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
95 		}
96 
97 		vlan = vlan->next;
98 	}
99 
100 	return 0;
101 }
102 
103 
vlan_dynamic_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)104 static void vlan_dynamic_remove(struct hostapd_data *hapd,
105 				struct hostapd_vlan *vlan)
106 {
107 	struct hostapd_vlan *next;
108 
109 	while (vlan) {
110 		next = vlan->next;
111 
112 #ifdef CONFIG_FULL_DYNAMIC_VLAN
113 		/* vlan_dellink() takes care of cleanup and interface removal */
114 		if (vlan->vlan_id != VLAN_ID_WILDCARD)
115 			vlan_dellink(vlan->ifname, hapd);
116 #else /* CONFIG_FULL_DYNAMIC_VLAN */
117 		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
118 		    vlan_if_remove(hapd, vlan)) {
119 			wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
120 				   "iface: %s: %s",
121 				   vlan->ifname, strerror(errno));
122 		}
123 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
124 
125 		vlan = next;
126 	}
127 }
128 
129 
vlan_init(struct hostapd_data * hapd)130 int vlan_init(struct hostapd_data *hapd)
131 {
132 #ifdef CONFIG_FULL_DYNAMIC_VLAN
133 	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
134 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
135 
136 	if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
137 	     hapd->conf->ssid.per_sta_vif) &&
138 	    !hapd->conf->vlan) {
139 		/* dynamic vlans enabled but no (or empty) vlan_file given */
140 		struct hostapd_vlan *vlan;
141 		vlan = os_zalloc(sizeof(*vlan));
142 		if (vlan == NULL) {
143 			wpa_printf(MSG_ERROR, "Out of memory while assigning "
144 				   "VLAN interfaces");
145 			return -1;
146 		}
147 
148 		vlan->vlan_id = VLAN_ID_WILDCARD;
149 		os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
150 			    hapd->conf->iface);
151 		vlan->next = hapd->conf->vlan;
152 		hapd->conf->vlan = vlan;
153 	}
154 
155 	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
156 		return -1;
157 
158         return 0;
159 }
160 
161 
vlan_deinit(struct hostapd_data * hapd)162 void vlan_deinit(struct hostapd_data *hapd)
163 {
164 	vlan_dynamic_remove(hapd, hapd->conf->vlan);
165 
166 #ifdef CONFIG_FULL_DYNAMIC_VLAN
167 	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
168 	hapd->full_dynamic_vlan = NULL;
169 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
170 }
171 
172 
vlan_add_dynamic(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vlan_id,struct vlan_description * vlan_desc)173 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
174 				       struct hostapd_vlan *vlan,
175 				       int vlan_id,
176 				       struct vlan_description *vlan_desc)
177 {
178 	struct hostapd_vlan *n;
179 	char ifname[IFNAMSIZ + 1], *pos;
180 
181 	if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
182 		return NULL;
183 
184 	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
185 		   __func__, vlan_id, vlan->ifname);
186 	os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
187 	pos = os_strchr(ifname, '#');
188 	if (pos == NULL)
189 		return NULL;
190 	*pos++ = '\0';
191 
192 	n = os_zalloc(sizeof(*n));
193 	if (n == NULL)
194 		return NULL;
195 
196 	n->vlan_id = vlan_id;
197 	if (vlan_desc)
198 		n->vlan_desc = *vlan_desc;
199 	n->dynamic_vlan = 1;
200 
201 	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
202 		    pos);
203 
204 	n->next = hapd->conf->vlan;
205 	hapd->conf->vlan = n;
206 
207 	/* hapd->conf->vlan needs this new VLAN here for WPA setup */
208 	if (vlan_if_add(hapd, n, 0)) {
209 		hapd->conf->vlan = n->next;
210 		os_free(n);
211 		n = NULL;
212 	}
213 
214 	return n;
215 }
216 
217 
vlan_remove_dynamic(struct hostapd_data * hapd,int vlan_id)218 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
219 {
220 	struct hostapd_vlan *vlan;
221 
222 	if (vlan_id <= 0)
223 		return 1;
224 
225 	wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
226 		   __func__, hapd->conf->iface, vlan_id);
227 
228 	vlan = hapd->conf->vlan;
229 	while (vlan) {
230 		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
231 			vlan->dynamic_vlan--;
232 			break;
233 		}
234 		vlan = vlan->next;
235 	}
236 
237 	if (vlan == NULL)
238 		return 1;
239 
240 	if (vlan->dynamic_vlan == 0) {
241 		vlan_if_remove(hapd, vlan);
242 #ifdef CONFIG_FULL_DYNAMIC_VLAN
243 		vlan_dellink(vlan->ifname, hapd);
244 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
245 	}
246 
247 	return 0;
248 }
249