add place-holder directory for the a3000 wd533c93 scsi controller implementation.
[AROS.git] / workbench / network / WirelessManager / src / ap / vlan_init.c
blobc9d166a8f346a895fc4773765d550dbeb87ba58e
1 /*
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>
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.
11 * Alternatively, this software may be distributed under the terms of BSD
12 * license.
14 * See README and COPYING for more details.
17 #include "utils/includes.h"
19 #include "utils/common.h"
20 #include "hostapd.h"
21 #include "ap_config.h"
22 #include "vlan_init.h"
25 #ifdef CONFIG_FULL_DYNAMIC_VLAN
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29 #include <linux/sockios.h>
30 #include <linux/if_vlan.h>
31 #include <linux/if_bridge.h>
33 #include "drivers/priv_netlink.h"
34 #include "utils/eloop.h"
37 struct full_dynamic_vlan {
38 int s; /* socket on which to listen for new/removed interfaces. */
42 static int ifconfig_helper(const char *if_name, int up)
44 int fd;
45 struct ifreq ifr;
47 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
48 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
49 "failed: %s", __func__, strerror(errno));
50 return -1;
53 os_memset(&ifr, 0, sizeof(ifr));
54 os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
56 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
57 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
58 "for interface %s: %s",
59 __func__, if_name, strerror(errno));
60 close(fd);
61 return -1;
64 if (up)
65 ifr.ifr_flags |= IFF_UP;
66 else
67 ifr.ifr_flags &= ~IFF_UP;
69 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
70 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
71 "for interface %s (up=%d): %s",
72 __func__, if_name, up, strerror(errno));
73 close(fd);
74 return -1;
77 close(fd);
78 return 0;
82 static int ifconfig_up(const char *if_name)
84 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
85 return ifconfig_helper(if_name, 1);
89 static int ifconfig_down(const char *if_name)
91 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
92 return ifconfig_helper(if_name, 0);
97 * These are only available in recent linux headers (without the leading
98 * underscore).
100 #define _GET_VLAN_REALDEV_NAME_CMD 8
101 #define _GET_VLAN_VID_CMD 9
103 /* This value should be 256 ONLY. If it is something else, then hostapd
104 * might crash!, as this value has been hard-coded in 2.4.x kernel
105 * bridging code.
107 #define MAX_BR_PORTS 256
109 static int br_delif(const char *br_name, const char *if_name)
111 int fd;
112 struct ifreq ifr;
113 unsigned long args[2];
114 int if_index;
116 wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
117 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
118 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
119 "failed: %s", __func__, strerror(errno));
120 return -1;
123 if_index = if_nametoindex(if_name);
125 if (if_index == 0) {
126 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
127 "interface index for '%s'",
128 __func__, if_name);
129 close(fd);
130 return -1;
133 args[0] = BRCTL_DEL_IF;
134 args[1] = if_index;
136 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
137 ifr.ifr_data = (__caddr_t) args;
139 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
140 /* No error if interface already removed. */
141 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
142 "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
143 "%s", __func__, br_name, if_name, strerror(errno));
144 close(fd);
145 return -1;
148 close(fd);
149 return 0;
154 Add interface 'if_name' to the bridge 'br_name'
156 returns -1 on error
157 returns 1 if the interface is already part of the bridge
158 returns 0 otherwise
160 static int br_addif(const char *br_name, const char *if_name)
162 int fd;
163 struct ifreq ifr;
164 unsigned long args[2];
165 int if_index;
167 wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
168 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
169 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
170 "failed: %s", __func__, strerror(errno));
171 return -1;
174 if_index = if_nametoindex(if_name);
176 if (if_index == 0) {
177 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
178 "interface index for '%s'",
179 __func__, if_name);
180 close(fd);
181 return -1;
184 args[0] = BRCTL_ADD_IF;
185 args[1] = if_index;
187 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
188 ifr.ifr_data = (__caddr_t) args;
190 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
191 if (errno == EBUSY) {
192 /* The interface is already added. */
193 close(fd);
194 return 1;
197 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
198 "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
199 "%s", __func__, br_name, if_name, strerror(errno));
200 close(fd);
201 return -1;
204 close(fd);
205 return 0;
209 static int br_delbr(const char *br_name)
211 int fd;
212 unsigned long arg[2];
214 wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
215 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
216 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
217 "failed: %s", __func__, strerror(errno));
218 return -1;
221 arg[0] = BRCTL_DEL_BRIDGE;
222 arg[1] = (unsigned long) br_name;
224 if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
225 /* No error if bridge already removed. */
226 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
227 "%s: %s", __func__, br_name, strerror(errno));
228 close(fd);
229 return -1;
232 close(fd);
233 return 0;
238 Add a bridge with the name 'br_name'.
240 returns -1 on error
241 returns 1 if the bridge already exists
242 returns 0 otherwise
244 static int br_addbr(const char *br_name)
246 int fd;
247 unsigned long arg[4];
248 struct ifreq ifr;
250 wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
251 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
252 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
253 "failed: %s", __func__, strerror(errno));
254 return -1;
257 arg[0] = BRCTL_ADD_BRIDGE;
258 arg[1] = (unsigned long) br_name;
260 if (ioctl(fd, SIOCGIFBR, arg) < 0) {
261 if (errno == EEXIST) {
262 /* The bridge is already added. */
263 close(fd);
264 return 1;
265 } else {
266 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
267 "failed for %s: %s",
268 __func__, br_name, strerror(errno));
269 close(fd);
270 return -1;
274 /* Decrease forwarding delay to avoid EAPOL timeouts. */
275 os_memset(&ifr, 0, sizeof(ifr));
276 os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
277 arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
278 arg[1] = 1;
279 arg[2] = 0;
280 arg[3] = 0;
281 ifr.ifr_data = (char *) &arg;
282 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
283 wpa_printf(MSG_ERROR, "VLAN: %s: "
284 "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
285 "%s: %s", __func__, br_name, strerror(errno));
286 /* Continue anyway */
289 close(fd);
290 return 0;
294 static int br_getnumports(const char *br_name)
296 int fd;
297 int i;
298 int port_cnt = 0;
299 unsigned long arg[4];
300 int ifindices[MAX_BR_PORTS];
301 struct ifreq ifr;
303 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
304 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
305 "failed: %s", __func__, strerror(errno));
306 return -1;
309 arg[0] = BRCTL_GET_PORT_LIST;
310 arg[1] = (unsigned long) ifindices;
311 arg[2] = MAX_BR_PORTS;
312 arg[3] = 0;
314 os_memset(ifindices, 0, sizeof(ifindices));
315 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
316 ifr.ifr_data = (__caddr_t) arg;
318 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
319 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
320 "failed for %s: %s",
321 __func__, br_name, strerror(errno));
322 close(fd);
323 return -1;
326 for (i = 1; i < MAX_BR_PORTS; i++) {
327 if (ifindices[i] > 0) {
328 port_cnt++;
332 close(fd);
333 return port_cnt;
337 static int vlan_rem(const char *if_name)
339 int fd;
340 struct vlan_ioctl_args if_request;
342 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
343 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
344 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
345 if_name);
346 return -1;
349 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
350 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
351 "failed: %s", __func__, strerror(errno));
352 return -1;
355 os_memset(&if_request, 0, sizeof(if_request));
357 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
358 if_request.cmd = DEL_VLAN_CMD;
360 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
361 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
362 "%s", __func__, if_name, strerror(errno));
363 close(fd);
364 return -1;
367 close(fd);
368 return 0;
373 Add a vlan interface with VLAN ID 'vid' and tagged interface
374 'if_name'.
376 returns -1 on error
377 returns 1 if the interface already exists
378 returns 0 otherwise
380 static int vlan_add(const char *if_name, int vid)
382 int fd;
383 struct vlan_ioctl_args if_request;
385 wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
386 if_name, vid);
387 ifconfig_up(if_name);
389 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
390 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
391 if_name);
392 return -1;
395 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
396 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
397 "failed: %s", __func__, strerror(errno));
398 return -1;
401 os_memset(&if_request, 0, sizeof(if_request));
403 /* Determine if a suitable vlan device already exists. */
405 os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
406 vid);
408 if_request.cmd = _GET_VLAN_VID_CMD;
410 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
412 if (if_request.u.VID == vid) {
413 if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
415 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
416 os_strncmp(if_request.u.device2, if_name,
417 sizeof(if_request.u.device2)) == 0) {
418 close(fd);
419 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
420 "if_name %s exists already",
421 if_request.device1);
422 return 1;
427 /* A suitable vlan device does not already exist, add one. */
429 os_memset(&if_request, 0, sizeof(if_request));
430 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
431 if_request.u.VID = vid;
432 if_request.cmd = ADD_VLAN_CMD;
434 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
435 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
436 "%s",
437 __func__, if_request.device1, strerror(errno));
438 close(fd);
439 return -1;
442 close(fd);
443 return 0;
447 static int vlan_set_name_type(unsigned int name_type)
449 int fd;
450 struct vlan_ioctl_args if_request;
452 wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
453 name_type);
454 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
455 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
456 "failed: %s", __func__, strerror(errno));
457 return -1;
460 os_memset(&if_request, 0, sizeof(if_request));
462 if_request.u.name_type = name_type;
463 if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
464 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
465 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
466 "name_type=%u failed: %s",
467 __func__, name_type, strerror(errno));
468 close(fd);
469 return -1;
472 close(fd);
473 return 0;
477 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
479 char vlan_ifname[IFNAMSIZ];
480 char br_name[IFNAMSIZ];
481 struct hostapd_vlan *vlan = hapd->conf->vlan;
482 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
484 wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
486 while (vlan) {
487 if (os_strcmp(ifname, vlan->ifname) == 0) {
489 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
490 vlan->vlan_id);
492 if (!br_addbr(br_name))
493 vlan->clean |= DVLAN_CLEAN_BR;
495 ifconfig_up(br_name);
497 if (tagged_interface) {
499 if (!vlan_add(tagged_interface, vlan->vlan_id))
500 vlan->clean |= DVLAN_CLEAN_VLAN;
502 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
503 "vlan%d", vlan->vlan_id);
505 if (!br_addif(br_name, vlan_ifname))
506 vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
508 ifconfig_up(vlan_ifname);
511 if (!br_addif(br_name, ifname))
512 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
514 ifconfig_up(ifname);
516 break;
518 vlan = vlan->next;
523 static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
525 char vlan_ifname[IFNAMSIZ];
526 char br_name[IFNAMSIZ];
527 struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
528 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
530 wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
532 first = prev = vlan;
534 while (vlan) {
535 if (os_strcmp(ifname, vlan->ifname) == 0) {
536 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
537 vlan->vlan_id);
539 if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
540 br_delif(br_name, vlan->ifname);
542 if (tagged_interface) {
543 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
544 "vlan%d", vlan->vlan_id);
545 if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
546 br_delif(br_name, vlan_ifname);
547 ifconfig_down(vlan_ifname);
549 if (vlan->clean & DVLAN_CLEAN_VLAN)
550 vlan_rem(vlan_ifname);
553 if ((vlan->clean & DVLAN_CLEAN_BR) &&
554 br_getnumports(br_name) == 0) {
555 ifconfig_down(br_name);
556 br_delbr(br_name);
559 if (vlan == first) {
560 hapd->conf->vlan = vlan->next;
561 } else {
562 prev->next = vlan->next;
564 os_free(vlan);
566 break;
568 prev = vlan;
569 vlan = vlan->next;
574 static void
575 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
576 struct hostapd_data *hapd)
578 struct ifinfomsg *ifi;
579 int attrlen, nlmsg_len, rta_len;
580 struct rtattr *attr;
582 if (len < sizeof(*ifi))
583 return;
585 ifi = NLMSG_DATA(h);
587 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
589 attrlen = h->nlmsg_len - nlmsg_len;
590 if (attrlen < 0)
591 return;
593 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
595 rta_len = RTA_ALIGN(sizeof(struct rtattr));
596 while (RTA_OK(attr, attrlen)) {
597 char ifname[IFNAMSIZ + 1];
599 if (attr->rta_type == IFLA_IFNAME) {
600 int n = attr->rta_len - rta_len;
601 if (n < 0)
602 break;
604 os_memset(ifname, 0, sizeof(ifname));
606 if ((size_t) n > sizeof(ifname))
607 n = sizeof(ifname);
608 os_memcpy(ifname, ((char *) attr) + rta_len, n);
610 if (del)
611 vlan_dellink(ifname, hapd);
612 else
613 vlan_newlink(ifname, hapd);
616 attr = RTA_NEXT(attr, attrlen);
621 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
623 char buf[8192];
624 int left;
625 struct sockaddr_nl from;
626 socklen_t fromlen;
627 struct nlmsghdr *h;
628 struct hostapd_data *hapd = eloop_ctx;
630 fromlen = sizeof(from);
631 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
632 (struct sockaddr *) &from, &fromlen);
633 if (left < 0) {
634 if (errno != EINTR && errno != EAGAIN)
635 wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
636 __func__, strerror(errno));
637 return;
640 h = (struct nlmsghdr *) buf;
641 while (left >= (int) sizeof(*h)) {
642 int len, plen;
644 len = h->nlmsg_len;
645 plen = len - sizeof(*h);
646 if (len > left || plen < 0) {
647 wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
648 "message: len=%d left=%d plen=%d",
649 len, left, plen);
650 break;
653 switch (h->nlmsg_type) {
654 case RTM_NEWLINK:
655 vlan_read_ifnames(h, plen, 0, hapd);
656 break;
657 case RTM_DELLINK:
658 vlan_read_ifnames(h, plen, 1, hapd);
659 break;
662 len = NLMSG_ALIGN(len);
663 left -= len;
664 h = (struct nlmsghdr *) ((char *) h + len);
667 if (left > 0) {
668 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
669 "netlink message", __func__, left);
674 static struct full_dynamic_vlan *
675 full_dynamic_vlan_init(struct hostapd_data *hapd)
677 struct sockaddr_nl local;
678 struct full_dynamic_vlan *priv;
680 priv = os_zalloc(sizeof(*priv));
681 if (priv == NULL)
682 return NULL;
684 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
686 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
687 if (priv->s < 0) {
688 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
689 "NETLINK_ROUTE) failed: %s",
690 __func__, strerror(errno));
691 os_free(priv);
692 return NULL;
695 os_memset(&local, 0, sizeof(local));
696 local.nl_family = AF_NETLINK;
697 local.nl_groups = RTMGRP_LINK;
698 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
699 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
700 __func__, strerror(errno));
701 close(priv->s);
702 os_free(priv);
703 return NULL;
706 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
708 close(priv->s);
709 os_free(priv);
710 return NULL;
713 return priv;
717 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
719 if (priv == NULL)
720 return;
721 eloop_unregister_read_sock(priv->s);
722 close(priv->s);
723 os_free(priv);
725 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
728 int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
729 struct hostapd_ssid *mssid, const char *dyn_vlan)
731 int i;
733 if (dyn_vlan == NULL)
734 return 0;
736 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
737 * functions for setting up dynamic broadcast keys. */
738 for (i = 0; i < 4; i++) {
739 if (mssid->wep.key[i] &&
740 hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
741 i == mssid->wep.idx, NULL, 0,
742 mssid->wep.key[i], mssid->wep.len[i])) {
743 wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
744 "encryption for dynamic VLAN");
745 return -1;
749 return 0;
753 static int vlan_dynamic_add(struct hostapd_data *hapd,
754 struct hostapd_vlan *vlan)
756 while (vlan) {
757 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
758 if (hapd->drv.vlan_if_add(hapd, vlan->ifname)) {
759 if (errno != EEXIST) {
760 wpa_printf(MSG_ERROR, "VLAN: Could "
761 "not add VLAN %s: %s",
762 vlan->ifname,
763 strerror(errno));
764 return -1;
767 #ifdef CONFIG_FULL_DYNAMIC_VLAN
768 ifconfig_up(vlan->ifname);
769 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
772 vlan = vlan->next;
775 return 0;
779 static void vlan_dynamic_remove(struct hostapd_data *hapd,
780 struct hostapd_vlan *vlan)
782 struct hostapd_vlan *next;
784 while (vlan) {
785 next = vlan->next;
787 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
788 hapd->drv.vlan_if_remove(hapd, vlan->ifname)) {
789 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
790 "iface: %s: %s",
791 vlan->ifname, strerror(errno));
793 #ifdef CONFIG_FULL_DYNAMIC_VLAN
794 if (vlan->clean)
795 vlan_dellink(vlan->ifname, hapd);
796 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
798 vlan = next;
803 int vlan_init(struct hostapd_data *hapd)
805 #ifdef CONFIG_FULL_DYNAMIC_VLAN
806 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
807 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
809 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
810 return -1;
812 return 0;
816 void vlan_deinit(struct hostapd_data *hapd)
818 vlan_dynamic_remove(hapd, hapd->conf->vlan);
820 #ifdef CONFIG_FULL_DYNAMIC_VLAN
821 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
822 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
826 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
827 struct hostapd_vlan *vlan,
828 int vlan_id)
830 struct hostapd_vlan *n;
831 char *ifname, *pos;
833 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
834 vlan->vlan_id != VLAN_ID_WILDCARD)
835 return NULL;
837 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
838 __func__, vlan_id, vlan->ifname);
839 ifname = os_strdup(vlan->ifname);
840 if (ifname == NULL)
841 return NULL;
842 pos = os_strchr(ifname, '#');
843 if (pos == NULL) {
844 os_free(ifname);
845 return NULL;
847 *pos++ = '\0';
849 n = os_zalloc(sizeof(*n));
850 if (n == NULL) {
851 os_free(ifname);
852 return NULL;
855 n->vlan_id = vlan_id;
856 n->dynamic_vlan = 1;
858 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
859 pos);
860 os_free(ifname);
862 if (hapd->drv.vlan_if_add(hapd, n->ifname)) {
863 os_free(n);
864 return NULL;
867 n->next = hapd->conf->vlan;
868 hapd->conf->vlan = n;
870 #ifdef CONFIG_FULL_DYNAMIC_VLAN
871 ifconfig_up(n->ifname);
872 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
874 return n;
878 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
880 struct hostapd_vlan *vlan;
882 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
883 return 1;
885 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
887 vlan = hapd->conf->vlan;
888 while (vlan) {
889 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
890 vlan->dynamic_vlan--;
891 break;
893 vlan = vlan->next;
896 if (vlan == NULL)
897 return 1;
899 if (vlan->dynamic_vlan == 0)
900 hapd->drv.vlan_if_remove(hapd, vlan->ifname);
902 return 0;