blob: fd1c8ddacee62e89eb9c929d7dbeb1d87f2e8654 [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"
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070012#ifdef CONFIG_FULL_DYNAMIC_VLAN
13#include <net/if.h>
14#include <sys/ioctl.h>
15#include <linux/sockios.h>
16#include <linux/if_vlan.h>
17#include <linux/if_bridge.h>
18#endif /* CONFIG_FULL_DYNAMIC_VLAN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019
20#include "utils/common.h"
21#include "hostapd.h"
22#include "ap_config.h"
23#include "ap_drv_ops.h"
24#include "vlan_init.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070025#include "vlan_util.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026
27
28#ifdef CONFIG_FULL_DYNAMIC_VLAN
29
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "drivers/priv_netlink.h"
31#include "utils/eloop.h"
32
33
34struct full_dynamic_vlan {
35 int s; /* socket on which to listen for new/removed interfaces. */
36};
37
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070038#define DVLAN_CLEAN_BR 0x1
39#define DVLAN_CLEAN_VLAN 0x2
40#define DVLAN_CLEAN_VLAN_PORT 0x4
41
42struct dynamic_iface {
43 char ifname[IFNAMSIZ + 1];
44 int usage;
45 int clean;
46 struct dynamic_iface *next;
47};
48
49
50/* Increment ref counter for ifname and add clean flag.
51 * If not in list, add it only if some flags are given.
52 */
53static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
54 int clean)
55{
56 struct dynamic_iface *next, **dynamic_ifaces;
57 struct hapd_interfaces *interfaces;
58
59 interfaces = hapd->iface->interfaces;
60 dynamic_ifaces = &interfaces->vlan_priv;
61
62 for (next = *dynamic_ifaces; next; next = next->next) {
63 if (os_strcmp(ifname, next->ifname) == 0)
64 break;
65 }
66
67 if (next) {
68 next->usage++;
69 next->clean |= clean;
70 return;
71 }
72
73 if (!clean)
74 return;
75
76 next = os_zalloc(sizeof(*next));
77 if (!next)
78 return;
79 os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
80 next->usage = 1;
81 next->clean = clean;
82 next->next = *dynamic_ifaces;
83 *dynamic_ifaces = next;
84}
85
86
87/* Decrement reference counter for given ifname.
88 * Return clean flag iff reference counter was decreased to zero, else zero
89 */
90static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
91{
92 struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
93 struct hapd_interfaces *interfaces;
94 int clean;
95
96 interfaces = hapd->iface->interfaces;
97 dynamic_ifaces = &interfaces->vlan_priv;
98
99 for (next = *dynamic_ifaces; next; next = next->next) {
100 if (os_strcmp(ifname, next->ifname) == 0)
101 break;
102 prev = next;
103 }
104
105 if (!next)
106 return 0;
107
108 next->usage--;
109 if (next->usage)
110 return 0;
111
112 if (prev)
113 prev->next = next->next;
114 else
115 *dynamic_ifaces = next->next;
116 clean = next->clean;
117 os_free(next);
118
119 return clean;
120}
121
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700122
123static int ifconfig_helper(const char *if_name, int up)
124{
125 int fd;
126 struct ifreq ifr;
127
128 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
129 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
130 "failed: %s", __func__, strerror(errno));
131 return -1;
132 }
133
134 os_memset(&ifr, 0, sizeof(ifr));
135 os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
136
137 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
138 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
139 "for interface %s: %s",
140 __func__, if_name, strerror(errno));
141 close(fd);
142 return -1;
143 }
144
145 if (up)
146 ifr.ifr_flags |= IFF_UP;
147 else
148 ifr.ifr_flags &= ~IFF_UP;
149
150 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
151 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
152 "for interface %s (up=%d): %s",
153 __func__, if_name, up, strerror(errno));
154 close(fd);
155 return -1;
156 }
157
158 close(fd);
159 return 0;
160}
161
162
163static int ifconfig_up(const char *if_name)
164{
165 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
166 return ifconfig_helper(if_name, 1);
167}
168
169
170static int ifconfig_down(const char *if_name)
171{
172 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
173 return ifconfig_helper(if_name, 0);
174}
175
176
177/*
178 * These are only available in recent linux headers (without the leading
179 * underscore).
180 */
181#define _GET_VLAN_REALDEV_NAME_CMD 8
182#define _GET_VLAN_VID_CMD 9
183
184/* This value should be 256 ONLY. If it is something else, then hostapd
185 * might crash!, as this value has been hard-coded in 2.4.x kernel
186 * bridging code.
187 */
188#define MAX_BR_PORTS 256
189
190static int br_delif(const char *br_name, const char *if_name)
191{
192 int fd;
193 struct ifreq ifr;
194 unsigned long args[2];
195 int if_index;
196
197 wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
198 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
199 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
200 "failed: %s", __func__, strerror(errno));
201 return -1;
202 }
203
204 if_index = if_nametoindex(if_name);
205
206 if (if_index == 0) {
207 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
208 "interface index for '%s'",
209 __func__, if_name);
210 close(fd);
211 return -1;
212 }
213
214 args[0] = BRCTL_DEL_IF;
215 args[1] = if_index;
216
217 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
218 ifr.ifr_data = (__caddr_t) args;
219
220 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
221 /* No error if interface already removed. */
222 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
223 "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
224 "%s", __func__, br_name, if_name, strerror(errno));
225 close(fd);
226 return -1;
227 }
228
229 close(fd);
230 return 0;
231}
232
233
234/*
235 Add interface 'if_name' to the bridge 'br_name'
236
237 returns -1 on error
238 returns 1 if the interface is already part of the bridge
239 returns 0 otherwise
240*/
241static int br_addif(const char *br_name, const char *if_name)
242{
243 int fd;
244 struct ifreq ifr;
245 unsigned long args[2];
246 int if_index;
247
248 wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
249 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
250 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
251 "failed: %s", __func__, strerror(errno));
252 return -1;
253 }
254
255 if_index = if_nametoindex(if_name);
256
257 if (if_index == 0) {
258 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
259 "interface index for '%s'",
260 __func__, if_name);
261 close(fd);
262 return -1;
263 }
264
265 args[0] = BRCTL_ADD_IF;
266 args[1] = if_index;
267
268 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
269 ifr.ifr_data = (__caddr_t) args;
270
271 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
272 if (errno == EBUSY) {
273 /* The interface is already added. */
274 close(fd);
275 return 1;
276 }
277
278 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
279 "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
280 "%s", __func__, br_name, if_name, strerror(errno));
281 close(fd);
282 return -1;
283 }
284
285 close(fd);
286 return 0;
287}
288
289
290static int br_delbr(const char *br_name)
291{
292 int fd;
293 unsigned long arg[2];
294
295 wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
296 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
297 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
298 "failed: %s", __func__, strerror(errno));
299 return -1;
300 }
301
302 arg[0] = BRCTL_DEL_BRIDGE;
303 arg[1] = (unsigned long) br_name;
304
305 if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
306 /* No error if bridge already removed. */
307 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
308 "%s: %s", __func__, br_name, strerror(errno));
309 close(fd);
310 return -1;
311 }
312
313 close(fd);
314 return 0;
315}
316
317
318/*
319 Add a bridge with the name 'br_name'.
320
321 returns -1 on error
322 returns 1 if the bridge already exists
323 returns 0 otherwise
324*/
325static int br_addbr(const char *br_name)
326{
327 int fd;
328 unsigned long arg[4];
329 struct ifreq ifr;
330
331 wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
332 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
333 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
334 "failed: %s", __func__, strerror(errno));
335 return -1;
336 }
337
338 arg[0] = BRCTL_ADD_BRIDGE;
339 arg[1] = (unsigned long) br_name;
340
341 if (ioctl(fd, SIOCGIFBR, arg) < 0) {
342 if (errno == EEXIST) {
343 /* The bridge is already added. */
344 close(fd);
345 return 1;
346 } else {
347 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
348 "failed for %s: %s",
349 __func__, br_name, strerror(errno));
350 close(fd);
351 return -1;
352 }
353 }
354
355 /* Decrease forwarding delay to avoid EAPOL timeouts. */
356 os_memset(&ifr, 0, sizeof(ifr));
357 os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
358 arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
359 arg[1] = 1;
360 arg[2] = 0;
361 arg[3] = 0;
362 ifr.ifr_data = (char *) &arg;
363 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
364 wpa_printf(MSG_ERROR, "VLAN: %s: "
365 "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
366 "%s: %s", __func__, br_name, strerror(errno));
367 /* Continue anyway */
368 }
369
370 close(fd);
371 return 0;
372}
373
374
375static int br_getnumports(const char *br_name)
376{
377 int fd;
378 int i;
379 int port_cnt = 0;
380 unsigned long arg[4];
381 int ifindices[MAX_BR_PORTS];
382 struct ifreq ifr;
383
384 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
385 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
386 "failed: %s", __func__, strerror(errno));
387 return -1;
388 }
389
390 arg[0] = BRCTL_GET_PORT_LIST;
391 arg[1] = (unsigned long) ifindices;
392 arg[2] = MAX_BR_PORTS;
393 arg[3] = 0;
394
395 os_memset(ifindices, 0, sizeof(ifindices));
396 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
397 ifr.ifr_data = (__caddr_t) arg;
398
399 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
400 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
401 "failed for %s: %s",
402 __func__, br_name, strerror(errno));
403 close(fd);
404 return -1;
405 }
406
407 for (i = 1; i < MAX_BR_PORTS; i++) {
408 if (ifindices[i] > 0) {
409 port_cnt++;
410 }
411 }
412
413 close(fd);
414 return port_cnt;
415}
416
417
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700418#ifndef CONFIG_VLAN_NETLINK
419
420int vlan_rem(const char *if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700421{
422 int fd;
423 struct vlan_ioctl_args if_request;
424
425 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
426 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
427 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
428 if_name);
429 return -1;
430 }
431
432 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
433 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
434 "failed: %s", __func__, strerror(errno));
435 return -1;
436 }
437
438 os_memset(&if_request, 0, sizeof(if_request));
439
440 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
441 if_request.cmd = DEL_VLAN_CMD;
442
443 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
444 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
445 "%s", __func__, if_name, strerror(errno));
446 close(fd);
447 return -1;
448 }
449
450 close(fd);
451 return 0;
452}
453
454
455/*
456 Add a vlan interface with VLAN ID 'vid' and tagged interface
457 'if_name'.
458
459 returns -1 on error
460 returns 1 if the interface already exists
461 returns 0 otherwise
462*/
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700463int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700464{
465 int fd;
466 struct vlan_ioctl_args if_request;
467
468 wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
469 if_name, vid);
470 ifconfig_up(if_name);
471
472 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
473 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
474 if_name);
475 return -1;
476 }
477
478 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
479 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
480 "failed: %s", __func__, strerror(errno));
481 return -1;
482 }
483
484 os_memset(&if_request, 0, sizeof(if_request));
485
486 /* Determine if a suitable vlan device already exists. */
487
488 os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
489 vid);
490
491 if_request.cmd = _GET_VLAN_VID_CMD;
492
493 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
494
495 if (if_request.u.VID == vid) {
496 if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
497
498 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
499 os_strncmp(if_request.u.device2, if_name,
500 sizeof(if_request.u.device2)) == 0) {
501 close(fd);
502 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
503 "if_name %s exists already",
504 if_request.device1);
505 return 1;
506 }
507 }
508 }
509
510 /* A suitable vlan device does not already exist, add one. */
511
512 os_memset(&if_request, 0, sizeof(if_request));
513 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
514 if_request.u.VID = vid;
515 if_request.cmd = ADD_VLAN_CMD;
516
517 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
518 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
519 "%s",
520 __func__, if_request.device1, strerror(errno));
521 close(fd);
522 return -1;
523 }
524
525 close(fd);
526 return 0;
527}
528
529
530static int vlan_set_name_type(unsigned int name_type)
531{
532 int fd;
533 struct vlan_ioctl_args if_request;
534
535 wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
536 name_type);
537 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
538 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
539 "failed: %s", __func__, strerror(errno));
540 return -1;
541 }
542
543 os_memset(&if_request, 0, sizeof(if_request));
544
545 if_request.u.name_type = name_type;
546 if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
547 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
548 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
549 "name_type=%u failed: %s",
550 __func__, name_type, strerror(errno));
551 close(fd);
552 return -1;
553 }
554
555 close(fd);
556 return 0;
557}
558
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700559#endif /* CONFIG_VLAN_NETLINK */
560
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700561
562static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
563{
564 char vlan_ifname[IFNAMSIZ];
565 char br_name[IFNAMSIZ];
566 struct hostapd_vlan *vlan = hapd->conf->vlan;
567 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700568 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700569 int clean;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700570
571 wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
572
573 while (vlan) {
Dmitry Shmidt83474442015-04-15 13:47:09 -0700574 if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
575 vlan->configured = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700576
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700577 if (hapd->conf->vlan_bridge[0]) {
578 os_snprintf(br_name, sizeof(br_name), "%s%d",
579 hapd->conf->vlan_bridge,
580 vlan->vlan_id);
581 } else if (tagged_interface) {
582 os_snprintf(br_name, sizeof(br_name),
583 "br%s.%d", tagged_interface,
584 vlan->vlan_id);
585 } else {
586 os_snprintf(br_name, sizeof(br_name),
587 "brvlan%d", vlan->vlan_id);
588 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700589
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700590 dyn_iface_get(hapd, br_name,
591 br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700592
593 ifconfig_up(br_name);
594
595 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700596 if (vlan_naming ==
597 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
598 os_snprintf(vlan_ifname,
599 sizeof(vlan_ifname),
600 "%s.%d", tagged_interface,
601 vlan->vlan_id);
602 else
603 os_snprintf(vlan_ifname,
604 sizeof(vlan_ifname),
605 "vlan%d", vlan->vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700606
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700607 clean = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700608 ifconfig_up(tagged_interface);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700609 if (!vlan_add(tagged_interface, vlan->vlan_id,
610 vlan_ifname))
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700611 clean |= DVLAN_CLEAN_VLAN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700612
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700613 if (!br_addif(br_name, vlan_ifname))
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700614 clean |= DVLAN_CLEAN_VLAN_PORT;
615
616 dyn_iface_get(hapd, vlan_ifname, clean);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700617
618 ifconfig_up(vlan_ifname);
619 }
620
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700621 if (!br_addif(br_name, ifname))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700622 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
623
624 ifconfig_up(ifname);
625
626 break;
627 }
628 vlan = vlan->next;
629 }
630}
631
632
633static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
634{
635 char vlan_ifname[IFNAMSIZ];
636 char br_name[IFNAMSIZ];
637 struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
638 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700639 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700640 int clean;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700641
642 wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
643
644 first = prev = vlan;
645
646 while (vlan) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700647 if (os_strcmp(ifname, vlan->ifname) == 0 &&
648 vlan->configured) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700649 if (hapd->conf->vlan_bridge[0]) {
650 os_snprintf(br_name, sizeof(br_name), "%s%d",
651 hapd->conf->vlan_bridge,
652 vlan->vlan_id);
653 } else if (tagged_interface) {
654 os_snprintf(br_name, sizeof(br_name),
655 "br%s.%d", tagged_interface,
656 vlan->vlan_id);
657 } else {
658 os_snprintf(br_name, sizeof(br_name),
659 "brvlan%d", vlan->vlan_id);
660 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700662 if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700663 br_delif(br_name, vlan->ifname);
664
665 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700666 if (vlan_naming ==
667 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
668 os_snprintf(vlan_ifname,
669 sizeof(vlan_ifname),
670 "%s.%d", tagged_interface,
671 vlan->vlan_id);
672 else
673 os_snprintf(vlan_ifname,
674 sizeof(vlan_ifname),
675 "vlan%d", vlan->vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700676
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700677 clean = dyn_iface_put(hapd, vlan_ifname);
678
679 if (clean & DVLAN_CLEAN_VLAN_PORT)
680 br_delif(br_name, vlan_ifname);
681
682 if (clean & DVLAN_CLEAN_VLAN) {
683 ifconfig_down(vlan_ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700684 vlan_rem(vlan_ifname);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700685 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700686 }
687
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700688 clean = dyn_iface_put(hapd, br_name);
689 if ((clean & DVLAN_CLEAN_BR) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700690 br_getnumports(br_name) == 0) {
691 ifconfig_down(br_name);
692 br_delbr(br_name);
693 }
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700694 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700695
Dmitry Shmidta3dc3092015-06-23 11:21:28 -0700696 if (os_strcmp(ifname, vlan->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700697 if (vlan == first) {
698 hapd->conf->vlan = vlan->next;
699 } else {
700 prev->next = vlan->next;
701 }
702 os_free(vlan);
703
704 break;
705 }
706 prev = vlan;
707 vlan = vlan->next;
708 }
709}
710
711
712static void
713vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
714 struct hostapd_data *hapd)
715{
716 struct ifinfomsg *ifi;
717 int attrlen, nlmsg_len, rta_len;
718 struct rtattr *attr;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800719 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720
721 if (len < sizeof(*ifi))
722 return;
723
724 ifi = NLMSG_DATA(h);
725
726 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
727
728 attrlen = h->nlmsg_len - nlmsg_len;
729 if (attrlen < 0)
730 return;
731
732 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
733
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800734 os_memset(ifname, 0, sizeof(ifname));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700735 rta_len = RTA_ALIGN(sizeof(struct rtattr));
736 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737 if (attr->rta_type == IFLA_IFNAME) {
738 int n = attr->rta_len - rta_len;
739 if (n < 0)
740 break;
741
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800742 if ((size_t) n >= sizeof(ifname))
743 n = sizeof(ifname) - 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700744 os_memcpy(ifname, ((char *) attr) + rta_len, n);
745
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746 }
747
748 attr = RTA_NEXT(attr, attrlen);
749 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800750
751 if (!ifname[0])
752 return;
Dmitry Shmidt83474442015-04-15 13:47:09 -0700753 if (del && if_nametoindex(ifname)) {
754 /* interface still exists, race condition ->
755 * iface has just been recreated */
756 return;
757 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800758
759 wpa_printf(MSG_DEBUG,
760 "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
761 del ? "DEL" : "NEW",
762 ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
763 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
764 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
765 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
766 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
767
768 if (del)
769 vlan_dellink(ifname, hapd);
770 else
771 vlan_newlink(ifname, hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700772}
773
774
775static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
776{
777 char buf[8192];
778 int left;
779 struct sockaddr_nl from;
780 socklen_t fromlen;
781 struct nlmsghdr *h;
782 struct hostapd_data *hapd = eloop_ctx;
783
784 fromlen = sizeof(from);
785 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
786 (struct sockaddr *) &from, &fromlen);
787 if (left < 0) {
788 if (errno != EINTR && errno != EAGAIN)
789 wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
790 __func__, strerror(errno));
791 return;
792 }
793
794 h = (struct nlmsghdr *) buf;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800795 while (NLMSG_OK(h, left)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796 int len, plen;
797
798 len = h->nlmsg_len;
799 plen = len - sizeof(*h);
800 if (len > left || plen < 0) {
801 wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
802 "message: len=%d left=%d plen=%d",
803 len, left, plen);
804 break;
805 }
806
807 switch (h->nlmsg_type) {
808 case RTM_NEWLINK:
809 vlan_read_ifnames(h, plen, 0, hapd);
810 break;
811 case RTM_DELLINK:
812 vlan_read_ifnames(h, plen, 1, hapd);
813 break;
814 }
815
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800816 h = NLMSG_NEXT(h, left);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700817 }
818
819 if (left > 0) {
820 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
821 "netlink message", __func__, left);
822 }
823}
824
825
826static struct full_dynamic_vlan *
827full_dynamic_vlan_init(struct hostapd_data *hapd)
828{
829 struct sockaddr_nl local;
830 struct full_dynamic_vlan *priv;
831
832 priv = os_zalloc(sizeof(*priv));
833 if (priv == NULL)
834 return NULL;
835
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700836#ifndef CONFIG_VLAN_NETLINK
837 vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
838 DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
839 VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
840 VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
841#endif /* CONFIG_VLAN_NETLINK */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700842
843 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
844 if (priv->s < 0) {
845 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
846 "NETLINK_ROUTE) failed: %s",
847 __func__, strerror(errno));
848 os_free(priv);
849 return NULL;
850 }
851
852 os_memset(&local, 0, sizeof(local));
853 local.nl_family = AF_NETLINK;
854 local.nl_groups = RTMGRP_LINK;
855 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
856 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
857 __func__, strerror(errno));
858 close(priv->s);
859 os_free(priv);
860 return NULL;
861 }
862
863 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
864 {
865 close(priv->s);
866 os_free(priv);
867 return NULL;
868 }
869
870 return priv;
871}
872
873
874static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
875{
876 if (priv == NULL)
877 return;
878 eloop_unregister_read_sock(priv->s);
879 close(priv->s);
880 os_free(priv);
881}
882#endif /* CONFIG_FULL_DYNAMIC_VLAN */
883
884
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700885int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700886{
887 int i;
888
889 if (dyn_vlan == NULL)
890 return 0;
891
892 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
893 * functions for setting up dynamic broadcast keys. */
894 for (i = 0; i < 4; i++) {
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700895 if (hapd->conf->ssid.wep.key[i] &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700896 hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700897 i == hapd->conf->ssid.wep.idx, NULL, 0,
898 hapd->conf->ssid.wep.key[i],
899 hapd->conf->ssid.wep.len[i]))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700900 {
901 wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
902 "encryption for dynamic VLAN");
903 return -1;
904 }
905 }
906
907 return 0;
908}
909
910
911static int vlan_dynamic_add(struct hostapd_data *hapd,
912 struct hostapd_vlan *vlan)
913{
914 while (vlan) {
915 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
916 if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
917 if (errno != EEXIST) {
918 wpa_printf(MSG_ERROR, "VLAN: Could "
919 "not add VLAN %s: %s",
920 vlan->ifname,
921 strerror(errno));
922 return -1;
923 }
924 }
925#ifdef CONFIG_FULL_DYNAMIC_VLAN
926 ifconfig_up(vlan->ifname);
927#endif /* CONFIG_FULL_DYNAMIC_VLAN */
928 }
929
930 vlan = vlan->next;
931 }
932
933 return 0;
934}
935
936
937static void vlan_dynamic_remove(struct hostapd_data *hapd,
938 struct hostapd_vlan *vlan)
939{
940 struct hostapd_vlan *next;
941
942 while (vlan) {
943 next = vlan->next;
944
945 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
946 hostapd_vlan_if_remove(hapd, vlan->ifname)) {
947 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
948 "iface: %s: %s",
949 vlan->ifname, strerror(errno));
950 }
951#ifdef CONFIG_FULL_DYNAMIC_VLAN
952 if (vlan->clean)
953 vlan_dellink(vlan->ifname, hapd);
954#endif /* CONFIG_FULL_DYNAMIC_VLAN */
955
956 vlan = next;
957 }
958}
959
960
961int vlan_init(struct hostapd_data *hapd)
962{
963#ifdef CONFIG_FULL_DYNAMIC_VLAN
964 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
965#endif /* CONFIG_FULL_DYNAMIC_VLAN */
966
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700967 if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
968 !hapd->conf->vlan) {
969 /* dynamic vlans enabled but no (or empty) vlan_file given */
970 struct hostapd_vlan *vlan;
971 vlan = os_zalloc(sizeof(*vlan));
972 if (vlan == NULL) {
973 wpa_printf(MSG_ERROR, "Out of memory while assigning "
974 "VLAN interfaces");
975 return -1;
976 }
977
978 vlan->vlan_id = VLAN_ID_WILDCARD;
979 os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
980 hapd->conf->iface);
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -0700981 vlan->next = hapd->conf->vlan;
982 hapd->conf->vlan = vlan;
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700983 }
984
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
986 return -1;
987
988 return 0;
989}
990
991
992void vlan_deinit(struct hostapd_data *hapd)
993{
994 vlan_dynamic_remove(hapd, hapd->conf->vlan);
995
996#ifdef CONFIG_FULL_DYNAMIC_VLAN
997 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700998 hapd->full_dynamic_vlan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700999#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1000}
1001
1002
1003struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
1004 struct hostapd_vlan *vlan,
1005 int vlan_id)
1006{
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001007 struct hostapd_vlan *n = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001008 char *ifname, *pos;
1009
1010 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
1011 vlan->vlan_id != VLAN_ID_WILDCARD)
1012 return NULL;
1013
1014 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
1015 __func__, vlan_id, vlan->ifname);
1016 ifname = os_strdup(vlan->ifname);
1017 if (ifname == NULL)
1018 return NULL;
1019 pos = os_strchr(ifname, '#');
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001020 if (pos == NULL)
1021 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001022 *pos++ = '\0';
1023
1024 n = os_zalloc(sizeof(*n));
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001025 if (n == NULL)
1026 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001027
1028 n->vlan_id = vlan_id;
1029 n->dynamic_vlan = 1;
1030
1031 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
1032 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001033
1034 if (hostapd_vlan_if_add(hapd, n->ifname)) {
1035 os_free(n);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001036 n = NULL;
1037 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001038 }
1039
1040 n->next = hapd->conf->vlan;
1041 hapd->conf->vlan = n;
1042
1043#ifdef CONFIG_FULL_DYNAMIC_VLAN
1044 ifconfig_up(n->ifname);
1045#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1046
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001047free_ifname:
1048 os_free(ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001049 return n;
1050}
1051
1052
1053int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
1054{
1055 struct hostapd_vlan *vlan;
1056
1057 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
1058 return 1;
1059
Dmitry Shmidt83474442015-04-15 13:47:09 -07001060 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
1061 __func__, hapd->conf->iface, vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001062
1063 vlan = hapd->conf->vlan;
1064 while (vlan) {
1065 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
1066 vlan->dynamic_vlan--;
1067 break;
1068 }
1069 vlan = vlan->next;
1070 }
1071
1072 if (vlan == NULL)
1073 return 1;
1074
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001075 if (vlan->dynamic_vlan == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001076 hostapd_vlan_if_remove(hapd, vlan->ifname);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001077#ifdef CONFIG_FULL_DYNAMIC_VLAN
1078 vlan_dellink(vlan->ifname, hapd);
1079#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1080 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001081
1082 return 0;
1083}