blob: 53eacfb458c8f6f239a1a7e84bcdcdf774e03813 [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{
Hai Shalomfdcde762020-04-02 11:19:20 -070025 int ret;
26#ifdef CONFIG_WEP
27 int i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080028
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 }
Hai Shalomfdcde762020-04-02 11:19:20 -070037#endif /* CONFIG_WEP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080038
Dmitry Shmidte4663042016-04-04 10:07:49 -070039 if (!iface_exists(vlan->ifname))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080040 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
Dmitry Shmidte4663042016-04-04 10:07:49 -070070int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080071{
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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070084static 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) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080089 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;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094 }
95#ifdef CONFIG_FULL_DYNAMIC_VLAN
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080096 vlan_newlink(vlan->ifname, hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070097#endif /* CONFIG_FULL_DYNAMIC_VLAN */
98 }
99
100 vlan = vlan->next;
101 }
102
103 return 0;
104}
105
106
107static 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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800115#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 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700120 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800121 vlan_if_remove(hapd, vlan)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700122 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
123 "iface: %s: %s",
124 vlan->ifname, strerror(errno));
125 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700126#endif /* CONFIG_FULL_DYNAMIC_VLAN */
127
128 vlan = next;
129 }
130}
131
132
133int 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
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800139 if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
140 hapd->conf->ssid.per_sta_vif) &&
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700141 !hapd->conf->vlan) {
142 /* dynamic vlans enabled but no (or empty) vlan_file given */
143 struct hostapd_vlan *vlan;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800144 int ret;
145
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700146 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;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800154 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 }
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -0700164 vlan->next = hapd->conf->vlan;
165 hapd->conf->vlan = vlan;
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700166 }
167
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700168 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
169 return -1;
170
171 return 0;
172}
173
174
175void 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);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700181 hapd->full_dynamic_vlan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182#endif /* CONFIG_FULL_DYNAMIC_VLAN */
183}
184
185
186struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
187 struct hostapd_vlan *vlan,
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800188 int vlan_id,
189 struct vlan_description *vlan_desc)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700190{
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800191 struct hostapd_vlan *n;
192 char ifname[IFNAMSIZ + 1], *pos;
Hai Shalom74f70d42019-02-11 14:42:39 -0800193 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700194
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800195 if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700196 return NULL;
197
198 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
199 __func__, vlan_id, vlan->ifname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800200 os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700201 pos = os_strchr(ifname, '#');
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800202 if (pos == NULL)
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800203 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204 *pos++ = '\0';
205
206 n = os_zalloc(sizeof(*n));
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800207 if (n == NULL)
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800208 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700209
210 n->vlan_id = vlan_id;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800211 if (vlan_desc)
212 n->vlan_desc = *vlan_desc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700213 n->dynamic_vlan = 1;
214
Hai Shalom74f70d42019-02-11 14:42:39 -0800215 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));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700222
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800223 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;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700229 os_free(n);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800230 n = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700231 }
232
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700233 return n;
234}
235
236
237int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
238{
239 struct hostapd_vlan *vlan;
240
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800241 if (vlan_id <= 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242 return 1;
243
Dmitry Shmidt83474442015-04-15 13:47:09 -0700244 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
245 __func__, hapd->conf->iface, vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
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
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700259 if (vlan->dynamic_vlan == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800260 vlan_if_remove(hapd, vlan);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700261#ifdef CONFIG_FULL_DYNAMIC_VLAN
262 vlan_dellink(vlan->ifname, hapd);
263#endif /* CONFIG_FULL_DYNAMIC_VLAN */
264 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700265
266 return 0;
267}