blob: 31e4fc6b396a14de5b3bd1f7f4cc6e5eedcb8bcf [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
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 *
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009 */
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"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080017#include "wpa_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018#include "vlan_init.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070019#include "vlan_util.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080022static 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
Dmitry Shmidte4663042016-04-04 10:07:49 -070036 if (!iface_exists(vlan->ifname))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080037 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
Dmitry Shmidte4663042016-04-04 10:07:49 -070067int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080068{
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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070081static 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) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080086 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;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070091 }
92#ifdef CONFIG_FULL_DYNAMIC_VLAN
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080093 vlan_newlink(vlan->ifname, hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094#endif /* CONFIG_FULL_DYNAMIC_VLAN */
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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800112#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 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800118 vlan_if_remove(hapd, vlan)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700119 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
120 "iface: %s: %s",
121 vlan->ifname, strerror(errno));
122 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700123#endif /* CONFIG_FULL_DYNAMIC_VLAN */
124
125 vlan = next;
126 }
127}
128
129
130int 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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800136 if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
137 hapd->conf->ssid.per_sta_vif) &&
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700138 !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);
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -0700151 vlan->next = hapd->conf->vlan;
152 hapd->conf->vlan = vlan;
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700153 }
154
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700155 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
156 return -1;
157
158 return 0;
159}
160
161
162void 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);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700168 hapd->full_dynamic_vlan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169#endif /* CONFIG_FULL_DYNAMIC_VLAN */
170}
171
172
173struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
174 struct hostapd_vlan *vlan,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800175 int vlan_id,
176 struct vlan_description *vlan_desc)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700177{
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800178 struct hostapd_vlan *n;
179 char ifname[IFNAMSIZ + 1], *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700180
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800181 if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182 return NULL;
183
184 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
185 __func__, vlan_id, vlan->ifname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800186 os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700187 pos = os_strchr(ifname, '#');
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800188 if (pos == NULL)
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800189 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700190 *pos++ = '\0';
191
192 n = os_zalloc(sizeof(*n));
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800193 if (n == NULL)
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800194 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700195
196 n->vlan_id = vlan_id;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800197 if (vlan_desc)
198 n->vlan_desc = *vlan_desc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700199 n->dynamic_vlan = 1;
200
201 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
202 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800204 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;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210 os_free(n);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800211 n = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700212 }
213
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700214 return n;
215}
216
217
218int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
219{
220 struct hostapd_vlan *vlan;
221
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800222 if (vlan_id <= 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223 return 1;
224
Dmitry Shmidt83474442015-04-15 13:47:09 -0700225 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
226 __func__, hapd->conf->iface, vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700227
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
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700240 if (vlan->dynamic_vlan == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800241 vlan_if_remove(hapd, vlan);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700242#ifdef CONFIG_FULL_DYNAMIC_VLAN
243 vlan_dellink(vlan->ifname, hapd);
244#endif /* CONFIG_FULL_DYNAMIC_VLAN */
245 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
247 return 0;
248}