]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/vlan_init.c
HE: Dynamically turn on TWT responder support
[thirdparty/hostap.git] / src / ap / vlan_init.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd / VLAN initialization
3 * Copyright 2003, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
36592d31 5 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6fc6879b 6 *
5f9c134a
JM
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
6fc6879b
JM
9 */
10
6226e38d 11#include "utils/includes.h"
6fc6879b 12
6226e38d 13#include "utils/common.h"
6fc6879b 14#include "hostapd.h"
6226e38d 15#include "ap_config.h"
3acdf771 16#include "ap_drv_ops.h"
7cebc8e2 17#include "wpa_auth.h"
6fc6879b 18#include "vlan_init.h"
03a6a2e9 19#include "vlan_util.h"
6fc6879b 20
6fc6879b 21
7cebc8e2
MB
22static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23 int existsok)
24{
41d62107
MB
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 }
7cebc8e2 35
e8685992 36 if (!iface_exists(vlan->ifname))
7cebc8e2
MB
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
59d63904 67int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
7cebc8e2
MB
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
6fc6879b
JM
81static int vlan_dynamic_add(struct hostapd_data *hapd,
82 struct hostapd_vlan *vlan)
83{
84 while (vlan) {
0249c988 85 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
7cebc8e2
MB
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;
6fc6879b 91 }
2de5a860 92#ifdef CONFIG_FULL_DYNAMIC_VLAN
7cebc8e2 93 vlan_newlink(vlan->ifname, hapd);
2de5a860 94#endif /* CONFIG_FULL_DYNAMIC_VLAN */
6fc6879b
JM
95 }
96
97 vlan = vlan->next;
98 }
99
100 return 0;
101}
102
103
104static 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
d0bdc96b
MB
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 */
6fc6879b 117 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
7cebc8e2 118 vlan_if_remove(hapd, vlan)) {
91faf6b9
JM
119 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
120 "iface: %s: %s",
121 vlan->ifname, strerror(errno));
6fc6879b 122 }
6fc6879b
JM
123#endif /* CONFIG_FULL_DYNAMIC_VLAN */
124
125 vlan = next;
126 }
127}
128
129
130int vlan_init(struct hostapd_data *hapd)
131{
6fc6879b
JM
132#ifdef CONFIG_FULL_DYNAMIC_VLAN
133 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
134#endif /* CONFIG_FULL_DYNAMIC_VLAN */
135
8be640b7
MB
136 if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
137 hapd->conf->ssid.per_sta_vif) &&
7ca902b5
MB
138 !hapd->conf->vlan) {
139 /* dynamic vlans enabled but no (or empty) vlan_file given */
140 struct hostapd_vlan *vlan;
68500d81
AO
141 int ret;
142
7ca902b5
MB
143 vlan = os_zalloc(sizeof(*vlan));
144 if (vlan == NULL) {
145 wpa_printf(MSG_ERROR, "Out of memory while assigning "
146 "VLAN interfaces");
147 return -1;
148 }
149
150 vlan->vlan_id = VLAN_ID_WILDCARD;
68500d81
AO
151 ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
152 hapd->conf->iface);
153 if (ret >= (int) sizeof(vlan->ifname)) {
154 wpa_printf(MSG_WARNING,
155 "VLAN: Interface name was truncated to %s",
156 vlan->ifname);
157 } else if (ret < 0) {
158 os_free(vlan);
159 return ret;
160 }
c2db79f2
MB
161 vlan->next = hapd->conf->vlan;
162 hapd->conf->vlan = vlan;
7ca902b5
MB
163 }
164
e34ce168
JM
165 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
166 return -1;
167
6fc6879b
JM
168 return 0;
169}
170
171
172void vlan_deinit(struct hostapd_data *hapd)
173{
174 vlan_dynamic_remove(hapd, hapd->conf->vlan);
175
176#ifdef CONFIG_FULL_DYNAMIC_VLAN
177 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
66f4dd15 178 hapd->full_dynamic_vlan = NULL;
6fc6879b
JM
179#endif /* CONFIG_FULL_DYNAMIC_VLAN */
180}
181
182
6fc6879b
JM
183struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
184 struct hostapd_vlan *vlan,
1889af2e
MB
185 int vlan_id,
186 struct vlan_description *vlan_desc)
6fc6879b 187{
cc9c805a
MB
188 struct hostapd_vlan *n;
189 char ifname[IFNAMSIZ + 1], *pos;
e422a819 190 int ret;
6fc6879b 191
1889af2e 192 if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
6fc6879b
JM
193 return NULL;
194
91faf6b9
JM
195 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
196 __func__, vlan_id, vlan->ifname);
cc9c805a 197 os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
6fc6879b 198 pos = os_strchr(ifname, '#');
66bc6830 199 if (pos == NULL)
cc9c805a 200 return NULL;
6fc6879b
JM
201 *pos++ = '\0';
202
203 n = os_zalloc(sizeof(*n));
66bc6830 204 if (n == NULL)
cc9c805a 205 return NULL;
6fc6879b
JM
206
207 n->vlan_id = vlan_id;
1889af2e
MB
208 if (vlan_desc)
209 n->vlan_desc = *vlan_desc;
6fc6879b
JM
210 n->dynamic_vlan = 1;
211
e422a819
JM
212 ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
213 ifname, vlan_id, pos);
214 if (os_snprintf_error(sizeof(n->ifname), ret)) {
215 os_free(n);
216 return NULL;
217 }
4d663233 218 os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
6fc6879b 219
7cebc8e2
MB
220 n->next = hapd->conf->vlan;
221 hapd->conf->vlan = n;
222
223 /* hapd->conf->vlan needs this new VLAN here for WPA setup */
224 if (vlan_if_add(hapd, n, 0)) {
225 hapd->conf->vlan = n->next;
6fc6879b 226 os_free(n);
66bc6830 227 n = NULL;
6fc6879b
JM
228 }
229
6fc6879b
JM
230 return n;
231}
232
233
234int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
235{
236 struct hostapd_vlan *vlan;
237
1889af2e 238 if (vlan_id <= 0)
6fc6879b
JM
239 return 1;
240
1acf38f1
JM
241 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
242 __func__, hapd->conf->iface, vlan_id);
91faf6b9 243
6fc6879b
JM
244 vlan = hapd->conf->vlan;
245 while (vlan) {
246 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
247 vlan->dynamic_vlan--;
248 break;
249 }
250 vlan = vlan->next;
251 }
252
253 if (vlan == NULL)
254 return 1;
255
132dfbe8 256 if (vlan->dynamic_vlan == 0) {
7cebc8e2 257 vlan_if_remove(hapd, vlan);
132dfbe8
MB
258#ifdef CONFIG_FULL_DYNAMIC_VLAN
259 vlan_dellink(vlan->ifname, hapd);
260#endif /* CONFIG_FULL_DYNAMIC_VLAN */
261 }
6fc6879b
JM
262
263 return 0;
264}