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