blob: 1afbb8ec9e8bcbe7b21dee23458a65943abc46f1 [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 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Alternatively, this software may be distributed under the terms of BSD
12 * license.
13 *
14 * See README and COPYING for more details.
15 */
16
17#include "utils/includes.h"
18
19#include "utils/common.h"
20#include "hostapd.h"
21#include "ap_config.h"
22#include "ap_drv_ops.h"
23#include "vlan_init.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070024#include "vlan_util.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070025
26
27#ifdef CONFIG_FULL_DYNAMIC_VLAN
28
29#include <net/if.h>
30#include <sys/ioctl.h>
31#include <linux/sockios.h>
32#include <linux/if_vlan.h>
33#include <linux/if_bridge.h>
34
35#include "drivers/priv_netlink.h"
36#include "utils/eloop.h"
37
38
39struct full_dynamic_vlan {
40 int s; /* socket on which to listen for new/removed interfaces. */
41};
42
43
44static int ifconfig_helper(const char *if_name, int up)
45{
46 int fd;
47 struct ifreq ifr;
48
49 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
50 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
51 "failed: %s", __func__, strerror(errno));
52 return -1;
53 }
54
55 os_memset(&ifr, 0, sizeof(ifr));
56 os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
57
58 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
59 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
60 "for interface %s: %s",
61 __func__, if_name, strerror(errno));
62 close(fd);
63 return -1;
64 }
65
66 if (up)
67 ifr.ifr_flags |= IFF_UP;
68 else
69 ifr.ifr_flags &= ~IFF_UP;
70
71 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
72 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
73 "for interface %s (up=%d): %s",
74 __func__, if_name, up, strerror(errno));
75 close(fd);
76 return -1;
77 }
78
79 close(fd);
80 return 0;
81}
82
83
84static int ifconfig_up(const char *if_name)
85{
86 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
87 return ifconfig_helper(if_name, 1);
88}
89
90
91static int ifconfig_down(const char *if_name)
92{
93 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
94 return ifconfig_helper(if_name, 0);
95}
96
97
98/*
99 * These are only available in recent linux headers (without the leading
100 * underscore).
101 */
102#define _GET_VLAN_REALDEV_NAME_CMD 8
103#define _GET_VLAN_VID_CMD 9
104
105/* This value should be 256 ONLY. If it is something else, then hostapd
106 * might crash!, as this value has been hard-coded in 2.4.x kernel
107 * bridging code.
108 */
109#define MAX_BR_PORTS 256
110
111static int br_delif(const char *br_name, const char *if_name)
112{
113 int fd;
114 struct ifreq ifr;
115 unsigned long args[2];
116 int if_index;
117
118 wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
119 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
120 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
121 "failed: %s", __func__, strerror(errno));
122 return -1;
123 }
124
125 if_index = if_nametoindex(if_name);
126
127 if (if_index == 0) {
128 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
129 "interface index for '%s'",
130 __func__, if_name);
131 close(fd);
132 return -1;
133 }
134
135 args[0] = BRCTL_DEL_IF;
136 args[1] = if_index;
137
138 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
139 ifr.ifr_data = (__caddr_t) args;
140
141 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
142 /* No error if interface already removed. */
143 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
144 "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
145 "%s", __func__, br_name, if_name, strerror(errno));
146 close(fd);
147 return -1;
148 }
149
150 close(fd);
151 return 0;
152}
153
154
155/*
156 Add interface 'if_name' to the bridge 'br_name'
157
158 returns -1 on error
159 returns 1 if the interface is already part of the bridge
160 returns 0 otherwise
161*/
162static int br_addif(const char *br_name, const char *if_name)
163{
164 int fd;
165 struct ifreq ifr;
166 unsigned long args[2];
167 int if_index;
168
169 wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
170 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
171 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
172 "failed: %s", __func__, strerror(errno));
173 return -1;
174 }
175
176 if_index = if_nametoindex(if_name);
177
178 if (if_index == 0) {
179 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
180 "interface index for '%s'",
181 __func__, if_name);
182 close(fd);
183 return -1;
184 }
185
186 args[0] = BRCTL_ADD_IF;
187 args[1] = if_index;
188
189 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
190 ifr.ifr_data = (__caddr_t) args;
191
192 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
193 if (errno == EBUSY) {
194 /* The interface is already added. */
195 close(fd);
196 return 1;
197 }
198
199 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
200 "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
201 "%s", __func__, br_name, if_name, strerror(errno));
202 close(fd);
203 return -1;
204 }
205
206 close(fd);
207 return 0;
208}
209
210
211static int br_delbr(const char *br_name)
212{
213 int fd;
214 unsigned long arg[2];
215
216 wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
217 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
218 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
219 "failed: %s", __func__, strerror(errno));
220 return -1;
221 }
222
223 arg[0] = BRCTL_DEL_BRIDGE;
224 arg[1] = (unsigned long) br_name;
225
226 if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
227 /* No error if bridge already removed. */
228 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
229 "%s: %s", __func__, br_name, strerror(errno));
230 close(fd);
231 return -1;
232 }
233
234 close(fd);
235 return 0;
236}
237
238
239/*
240 Add a bridge with the name 'br_name'.
241
242 returns -1 on error
243 returns 1 if the bridge already exists
244 returns 0 otherwise
245*/
246static int br_addbr(const char *br_name)
247{
248 int fd;
249 unsigned long arg[4];
250 struct ifreq ifr;
251
252 wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
253 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
254 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
255 "failed: %s", __func__, strerror(errno));
256 return -1;
257 }
258
259 arg[0] = BRCTL_ADD_BRIDGE;
260 arg[1] = (unsigned long) br_name;
261
262 if (ioctl(fd, SIOCGIFBR, arg) < 0) {
263 if (errno == EEXIST) {
264 /* The bridge is already added. */
265 close(fd);
266 return 1;
267 } else {
268 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
269 "failed for %s: %s",
270 __func__, br_name, strerror(errno));
271 close(fd);
272 return -1;
273 }
274 }
275
276 /* Decrease forwarding delay to avoid EAPOL timeouts. */
277 os_memset(&ifr, 0, sizeof(ifr));
278 os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
279 arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
280 arg[1] = 1;
281 arg[2] = 0;
282 arg[3] = 0;
283 ifr.ifr_data = (char *) &arg;
284 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
285 wpa_printf(MSG_ERROR, "VLAN: %s: "
286 "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
287 "%s: %s", __func__, br_name, strerror(errno));
288 /* Continue anyway */
289 }
290
291 close(fd);
292 return 0;
293}
294
295
296static int br_getnumports(const char *br_name)
297{
298 int fd;
299 int i;
300 int port_cnt = 0;
301 unsigned long arg[4];
302 int ifindices[MAX_BR_PORTS];
303 struct ifreq ifr;
304
305 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
306 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
307 "failed: %s", __func__, strerror(errno));
308 return -1;
309 }
310
311 arg[0] = BRCTL_GET_PORT_LIST;
312 arg[1] = (unsigned long) ifindices;
313 arg[2] = MAX_BR_PORTS;
314 arg[3] = 0;
315
316 os_memset(ifindices, 0, sizeof(ifindices));
317 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
318 ifr.ifr_data = (__caddr_t) arg;
319
320 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
321 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
322 "failed for %s: %s",
323 __func__, br_name, strerror(errno));
324 close(fd);
325 return -1;
326 }
327
328 for (i = 1; i < MAX_BR_PORTS; i++) {
329 if (ifindices[i] > 0) {
330 port_cnt++;
331 }
332 }
333
334 close(fd);
335 return port_cnt;
336}
337
338
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700339#ifndef CONFIG_VLAN_NETLINK
340
341int vlan_rem(const char *if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342{
343 int fd;
344 struct vlan_ioctl_args if_request;
345
346 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
347 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
348 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
349 if_name);
350 return -1;
351 }
352
353 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
354 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
355 "failed: %s", __func__, strerror(errno));
356 return -1;
357 }
358
359 os_memset(&if_request, 0, sizeof(if_request));
360
361 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
362 if_request.cmd = DEL_VLAN_CMD;
363
364 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
365 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
366 "%s", __func__, if_name, strerror(errno));
367 close(fd);
368 return -1;
369 }
370
371 close(fd);
372 return 0;
373}
374
375
376/*
377 Add a vlan interface with VLAN ID 'vid' and tagged interface
378 'if_name'.
379
380 returns -1 on error
381 returns 1 if the interface already exists
382 returns 0 otherwise
383*/
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700384int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385{
386 int fd;
387 struct vlan_ioctl_args if_request;
388
389 wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
390 if_name, vid);
391 ifconfig_up(if_name);
392
393 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
394 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
395 if_name);
396 return -1;
397 }
398
399 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
400 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
401 "failed: %s", __func__, strerror(errno));
402 return -1;
403 }
404
405 os_memset(&if_request, 0, sizeof(if_request));
406
407 /* Determine if a suitable vlan device already exists. */
408
409 os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
410 vid);
411
412 if_request.cmd = _GET_VLAN_VID_CMD;
413
414 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
415
416 if (if_request.u.VID == vid) {
417 if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
418
419 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
420 os_strncmp(if_request.u.device2, if_name,
421 sizeof(if_request.u.device2)) == 0) {
422 close(fd);
423 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
424 "if_name %s exists already",
425 if_request.device1);
426 return 1;
427 }
428 }
429 }
430
431 /* A suitable vlan device does not already exist, add one. */
432
433 os_memset(&if_request, 0, sizeof(if_request));
434 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
435 if_request.u.VID = vid;
436 if_request.cmd = ADD_VLAN_CMD;
437
438 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
439 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
440 "%s",
441 __func__, if_request.device1, strerror(errno));
442 close(fd);
443 return -1;
444 }
445
446 close(fd);
447 return 0;
448}
449
450
451static int vlan_set_name_type(unsigned int name_type)
452{
453 int fd;
454 struct vlan_ioctl_args if_request;
455
456 wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
457 name_type);
458 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
459 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
460 "failed: %s", __func__, strerror(errno));
461 return -1;
462 }
463
464 os_memset(&if_request, 0, sizeof(if_request));
465
466 if_request.u.name_type = name_type;
467 if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
468 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
469 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
470 "name_type=%u failed: %s",
471 __func__, name_type, strerror(errno));
472 close(fd);
473 return -1;
474 }
475
476 close(fd);
477 return 0;
478}
479
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700480#endif /* CONFIG_VLAN_NETLINK */
481
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700482
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700483/**
484 * Increase the usage counter for given parent/ifname combination.
485 * If create is set, then this iface is added to the global list.
486 * Returns
487 * -1 on error
488 * 0 if iface is not in list
489 * 1 if iface is in list (was there or has been added)
490 */
491static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
492 int create, struct hostapd_data *hapd)
493{
494 size_t i;
495 struct hostapd_dynamic_iface *j = NULL, **tmp;
496 struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
497
498 if (!parent)
499 parent = "";
500
501 for (i = 0; i < hapd_global->count_dynamic; i++) {
502 j = hapd_global->dynamic_iface[i];
503 if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
504 os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
505 break;
506 }
507 if (i < hapd_global->count_dynamic) {
508 j->usage++;
509 return 1;
510 }
511
512 /* new entry required */
513 if (!create)
514 return 0;
515
516 j = os_zalloc(sizeof(*j));
517 if (!j)
518 return -1;
519 os_strlcpy(j->iface, ifname, sizeof(j->iface));
520 os_strlcpy(j->parent, parent, sizeof(j->parent));
521
522 tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
523 sizeof(*hapd_global->dynamic_iface));
524 if (!tmp) {
525 wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
526 __func__);
527 return -1;
528 }
529 hapd_global->count_dynamic++;
530 hapd_global->dynamic_iface = tmp;
531 hapd_global->dynamic_iface[i] = j;
532
533 return 1;
534}
535
536
537/**
538 * Decrease the usage counter for given ifname.
539 * Returns
540 * -1 on error or if iface was not found
541 * 0 if iface was found and is still present
542 * 1 if iface was removed from global list
543 */
544static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
545 struct hostapd_data *hapd)
546{
547 size_t i;
548 struct hostapd_dynamic_iface *j = NULL, **tmp;
549 struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
550
551 if (!parent)
552 parent = "";
553
554 for (i = 0; i < hapd_glob->count_dynamic; i++) {
555 j = hapd_glob->dynamic_iface[i];
556 if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
557 os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
558 break;
559 }
560
561 if (i == hapd_glob->count_dynamic) {
562 /*
563 * Interface not in global list. This can happen if alloc in
564 * _get_ failed.
565 */
566 return -1;
567 }
568
569 if (j->usage > 0) {
570 j->usage--;
571 return 0;
572 }
573
574 os_free(j);
575 for (; i < hapd_glob->count_dynamic - 1; i++)
576 hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
577 hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
578 hapd_glob->count_dynamic--;
579
580 if (hapd_glob->count_dynamic == 0) {
581 os_free(hapd_glob->dynamic_iface);
582 hapd_glob->dynamic_iface = NULL;
583 return 1;
584 }
585
586 tmp = os_realloc_array(hapd_glob->dynamic_iface,
587 hapd_glob->count_dynamic,
588 sizeof(*hapd_glob->dynamic_iface));
589 if (!tmp) {
590 wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
591 __func__);
592 return -1;
593 }
594 hapd_glob->dynamic_iface = tmp;
595
596 return 1;
597}
598
599
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700600static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
601{
602 char vlan_ifname[IFNAMSIZ];
603 char br_name[IFNAMSIZ];
604 struct hostapd_vlan *vlan = hapd->conf->vlan;
605 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700606 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700607 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700608
609 wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
610
611 while (vlan) {
612 if (os_strcmp(ifname, vlan->ifname) == 0) {
613
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700614 if (hapd->conf->vlan_bridge[0]) {
615 os_snprintf(br_name, sizeof(br_name), "%s%d",
616 hapd->conf->vlan_bridge,
617 vlan->vlan_id);
618 } else if (tagged_interface) {
619 os_snprintf(br_name, sizeof(br_name),
620 "br%s.%d", tagged_interface,
621 vlan->vlan_id);
622 } else {
623 os_snprintf(br_name, sizeof(br_name),
624 "brvlan%d", vlan->vlan_id);
625 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700626
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700627 ret = br_addbr(br_name);
628 if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
629 hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700630 vlan->clean |= DVLAN_CLEAN_BR;
631
632 ifconfig_up(br_name);
633
634 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700635 if (vlan_naming ==
636 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
637 os_snprintf(vlan_ifname,
638 sizeof(vlan_ifname),
639 "%s.%d", tagged_interface,
640 vlan->vlan_id);
641 else
642 os_snprintf(vlan_ifname,
643 sizeof(vlan_ifname),
644 "vlan%d", vlan->vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700645
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700646 ifconfig_up(tagged_interface);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700647 ret = vlan_add(tagged_interface, vlan->vlan_id,
648 vlan_ifname);
649 if (hapd_get_dynamic_iface(NULL, vlan_ifname,
650 ret == 0, hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700651 vlan->clean |= DVLAN_CLEAN_VLAN;
652
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700653 ret = br_addif(br_name, vlan_ifname);
654 if (hapd_get_dynamic_iface(br_name,
655 vlan_ifname,
656 ret == 0, hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700657 vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
658
659 ifconfig_up(vlan_ifname);
660 }
661
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700662 ret = br_addif(br_name, ifname);
663 if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
664 hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700665 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
666
667 ifconfig_up(ifname);
668
669 break;
670 }
671 vlan = vlan->next;
672 }
673}
674
675
676static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
677{
678 char vlan_ifname[IFNAMSIZ];
679 char br_name[IFNAMSIZ];
680 struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
681 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700682 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700683
684 wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
685
686 first = prev = vlan;
687
688 while (vlan) {
689 if (os_strcmp(ifname, vlan->ifname) == 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700690 if (hapd->conf->vlan_bridge[0]) {
691 os_snprintf(br_name, sizeof(br_name), "%s%d",
692 hapd->conf->vlan_bridge,
693 vlan->vlan_id);
694 } else if (tagged_interface) {
695 os_snprintf(br_name, sizeof(br_name),
696 "br%s.%d", tagged_interface,
697 vlan->vlan_id);
698 } else {
699 os_snprintf(br_name, sizeof(br_name),
700 "brvlan%d", vlan->vlan_id);
701 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700702
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700703 if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
704 hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700705 br_delif(br_name, vlan->ifname);
706
707 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700708 if (vlan_naming ==
709 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
710 os_snprintf(vlan_ifname,
711 sizeof(vlan_ifname),
712 "%s.%d", tagged_interface,
713 vlan->vlan_id);
714 else
715 os_snprintf(vlan_ifname,
716 sizeof(vlan_ifname),
717 "vlan%d", vlan->vlan_id);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700718 if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
719 hapd_put_dynamic_iface(br_name, vlan_ifname,
720 hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700721 br_delif(br_name, vlan_ifname);
722 ifconfig_down(vlan_ifname);
723
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700724 if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
725 hapd_put_dynamic_iface(NULL, vlan_ifname,
726 hapd))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700727 vlan_rem(vlan_ifname);
728 }
729
730 if ((vlan->clean & DVLAN_CLEAN_BR) &&
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700731 hapd_put_dynamic_iface(NULL, br_name, hapd) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700732 br_getnumports(br_name) == 0) {
733 ifconfig_down(br_name);
734 br_delbr(br_name);
735 }
736
737 if (vlan == first) {
738 hapd->conf->vlan = vlan->next;
739 } else {
740 prev->next = vlan->next;
741 }
742 os_free(vlan);
743
744 break;
745 }
746 prev = vlan;
747 vlan = vlan->next;
748 }
749}
750
751
752static void
753vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
754 struct hostapd_data *hapd)
755{
756 struct ifinfomsg *ifi;
757 int attrlen, nlmsg_len, rta_len;
758 struct rtattr *attr;
759
760 if (len < sizeof(*ifi))
761 return;
762
763 ifi = NLMSG_DATA(h);
764
765 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
766
767 attrlen = h->nlmsg_len - nlmsg_len;
768 if (attrlen < 0)
769 return;
770
771 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
772
773 rta_len = RTA_ALIGN(sizeof(struct rtattr));
774 while (RTA_OK(attr, attrlen)) {
775 char ifname[IFNAMSIZ + 1];
776
777 if (attr->rta_type == IFLA_IFNAME) {
778 int n = attr->rta_len - rta_len;
779 if (n < 0)
780 break;
781
782 os_memset(ifname, 0, sizeof(ifname));
783
784 if ((size_t) n > sizeof(ifname))
785 n = sizeof(ifname);
786 os_memcpy(ifname, ((char *) attr) + rta_len, n);
787
788 if (del)
789 vlan_dellink(ifname, hapd);
790 else
791 vlan_newlink(ifname, hapd);
792 }
793
794 attr = RTA_NEXT(attr, attrlen);
795 }
796}
797
798
799static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
800{
801 char buf[8192];
802 int left;
803 struct sockaddr_nl from;
804 socklen_t fromlen;
805 struct nlmsghdr *h;
806 struct hostapd_data *hapd = eloop_ctx;
807
808 fromlen = sizeof(from);
809 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
810 (struct sockaddr *) &from, &fromlen);
811 if (left < 0) {
812 if (errno != EINTR && errno != EAGAIN)
813 wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
814 __func__, strerror(errno));
815 return;
816 }
817
818 h = (struct nlmsghdr *) buf;
819 while (left >= (int) sizeof(*h)) {
820 int len, plen;
821
822 len = h->nlmsg_len;
823 plen = len - sizeof(*h);
824 if (len > left || plen < 0) {
825 wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
826 "message: len=%d left=%d plen=%d",
827 len, left, plen);
828 break;
829 }
830
831 switch (h->nlmsg_type) {
832 case RTM_NEWLINK:
833 vlan_read_ifnames(h, plen, 0, hapd);
834 break;
835 case RTM_DELLINK:
836 vlan_read_ifnames(h, plen, 1, hapd);
837 break;
838 }
839
840 len = NLMSG_ALIGN(len);
841 left -= len;
842 h = (struct nlmsghdr *) ((char *) h + len);
843 }
844
845 if (left > 0) {
846 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
847 "netlink message", __func__, left);
848 }
849}
850
851
852static struct full_dynamic_vlan *
853full_dynamic_vlan_init(struct hostapd_data *hapd)
854{
855 struct sockaddr_nl local;
856 struct full_dynamic_vlan *priv;
857
858 priv = os_zalloc(sizeof(*priv));
859 if (priv == NULL)
860 return NULL;
861
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700862#ifndef CONFIG_VLAN_NETLINK
863 vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
864 DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
865 VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
866 VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
867#endif /* CONFIG_VLAN_NETLINK */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700868
869 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
870 if (priv->s < 0) {
871 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
872 "NETLINK_ROUTE) failed: %s",
873 __func__, strerror(errno));
874 os_free(priv);
875 return NULL;
876 }
877
878 os_memset(&local, 0, sizeof(local));
879 local.nl_family = AF_NETLINK;
880 local.nl_groups = RTMGRP_LINK;
881 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
882 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
883 __func__, strerror(errno));
884 close(priv->s);
885 os_free(priv);
886 return NULL;
887 }
888
889 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
890 {
891 close(priv->s);
892 os_free(priv);
893 return NULL;
894 }
895
896 return priv;
897}
898
899
900static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
901{
902 if (priv == NULL)
903 return;
904 eloop_unregister_read_sock(priv->s);
905 close(priv->s);
906 os_free(priv);
907}
908#endif /* CONFIG_FULL_DYNAMIC_VLAN */
909
910
911int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
912 struct hostapd_ssid *mssid, const char *dyn_vlan)
913{
914 int i;
915
916 if (dyn_vlan == NULL)
917 return 0;
918
919 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
920 * functions for setting up dynamic broadcast keys. */
921 for (i = 0; i < 4; i++) {
922 if (mssid->wep.key[i] &&
923 hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
924 i == mssid->wep.idx, NULL, 0,
925 mssid->wep.key[i], mssid->wep.len[i]))
926 {
927 wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
928 "encryption for dynamic VLAN");
929 return -1;
930 }
931 }
932
933 return 0;
934}
935
936
937static int vlan_dynamic_add(struct hostapd_data *hapd,
938 struct hostapd_vlan *vlan)
939{
940 while (vlan) {
941 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
942 if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
943 if (errno != EEXIST) {
944 wpa_printf(MSG_ERROR, "VLAN: Could "
945 "not add VLAN %s: %s",
946 vlan->ifname,
947 strerror(errno));
948 return -1;
949 }
950 }
951#ifdef CONFIG_FULL_DYNAMIC_VLAN
952 ifconfig_up(vlan->ifname);
953#endif /* CONFIG_FULL_DYNAMIC_VLAN */
954 }
955
956 vlan = vlan->next;
957 }
958
959 return 0;
960}
961
962
963static void vlan_dynamic_remove(struct hostapd_data *hapd,
964 struct hostapd_vlan *vlan)
965{
966 struct hostapd_vlan *next;
967
968 while (vlan) {
969 next = vlan->next;
970
971 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
972 hostapd_vlan_if_remove(hapd, vlan->ifname)) {
973 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
974 "iface: %s: %s",
975 vlan->ifname, strerror(errno));
976 }
977#ifdef CONFIG_FULL_DYNAMIC_VLAN
978 if (vlan->clean)
979 vlan_dellink(vlan->ifname, hapd);
980#endif /* CONFIG_FULL_DYNAMIC_VLAN */
981
982 vlan = next;
983 }
984}
985
986
987int vlan_init(struct hostapd_data *hapd)
988{
989#ifdef CONFIG_FULL_DYNAMIC_VLAN
990 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
991#endif /* CONFIG_FULL_DYNAMIC_VLAN */
992
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700993 if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
994 !hapd->conf->vlan) {
995 /* dynamic vlans enabled but no (or empty) vlan_file given */
996 struct hostapd_vlan *vlan;
997 vlan = os_zalloc(sizeof(*vlan));
998 if (vlan == NULL) {
999 wpa_printf(MSG_ERROR, "Out of memory while assigning "
1000 "VLAN interfaces");
1001 return -1;
1002 }
1003
1004 vlan->vlan_id = VLAN_ID_WILDCARD;
1005 os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
1006 hapd->conf->iface);
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07001007 vlan->next = hapd->conf->vlan;
1008 hapd->conf->vlan = vlan;
Dmitry Shmidt4b060592013-04-29 16:42:49 -07001009 }
1010
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001011 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
1012 return -1;
1013
1014 return 0;
1015}
1016
1017
1018void vlan_deinit(struct hostapd_data *hapd)
1019{
1020 vlan_dynamic_remove(hapd, hapd->conf->vlan);
1021
1022#ifdef CONFIG_FULL_DYNAMIC_VLAN
1023 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
Dmitry Shmidt56052862013-10-04 10:23:25 -07001024 hapd->full_dynamic_vlan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001025#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1026}
1027
1028
1029struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
1030 struct hostapd_vlan *vlan,
1031 int vlan_id)
1032{
1033 struct hostapd_vlan *n;
1034 char *ifname, *pos;
1035
1036 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
1037 vlan->vlan_id != VLAN_ID_WILDCARD)
1038 return NULL;
1039
1040 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
1041 __func__, vlan_id, vlan->ifname);
1042 ifname = os_strdup(vlan->ifname);
1043 if (ifname == NULL)
1044 return NULL;
1045 pos = os_strchr(ifname, '#');
1046 if (pos == NULL) {
1047 os_free(ifname);
1048 return NULL;
1049 }
1050 *pos++ = '\0';
1051
1052 n = os_zalloc(sizeof(*n));
1053 if (n == NULL) {
1054 os_free(ifname);
1055 return NULL;
1056 }
1057
1058 n->vlan_id = vlan_id;
1059 n->dynamic_vlan = 1;
1060
1061 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
1062 pos);
1063 os_free(ifname);
1064
1065 if (hostapd_vlan_if_add(hapd, n->ifname)) {
1066 os_free(n);
1067 return NULL;
1068 }
1069
1070 n->next = hapd->conf->vlan;
1071 hapd->conf->vlan = n;
1072
1073#ifdef CONFIG_FULL_DYNAMIC_VLAN
1074 ifconfig_up(n->ifname);
1075#endif /* CONFIG_FULL_DYNAMIC_VLAN */
1076
1077 return n;
1078}
1079
1080
1081int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
1082{
1083 struct hostapd_vlan *vlan;
1084
1085 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
1086 return 1;
1087
1088 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
1089
1090 vlan = hapd->conf->vlan;
1091 while (vlan) {
1092 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
1093 vlan->dynamic_vlan--;
1094 break;
1095 }
1096 vlan = vlan->next;
1097 }
1098
1099 if (vlan == NULL)
1100 return 1;
1101
1102 if (vlan->dynamic_vlan == 0)
1103 hostapd_vlan_if_remove(hapd, vlan->ifname);
1104
1105 return 0;
1106}