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
14 * See README and COPYING for more details.
17 #include "utils/includes.h"
19 #include "utils/common.h"
21 #include "ap_config.h"
22 #include "vlan_init.h"
25 #ifdef CONFIG_FULL_DYNAMIC_VLAN
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
)
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
));
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
));
65 ifr
.ifr_flags
|= IFF_UP
;
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
));
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
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
107 #define MAX_BR_PORTS 256
109 static int br_delif(const char *br_name
, const char *if_name
)
113 unsigned long args
[2];
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
));
123 if_index
= if_nametoindex(if_name
);
126 wpa_printf(MSG_ERROR
, "VLAN: %s: Failure determining "
127 "interface index for '%s'",
133 args
[0] = BRCTL_DEL_IF
;
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
));
154 Add interface 'if_name' to the bridge 'br_name'
157 returns 1 if the interface is already part of the bridge
160 static int br_addif(const char *br_name
, const char *if_name
)
164 unsigned long args
[2];
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
));
174 if_index
= if_nametoindex(if_name
);
177 wpa_printf(MSG_ERROR
, "VLAN: %s: Failure determining "
178 "interface index for '%s'",
184 args
[0] = BRCTL_ADD_IF
;
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. */
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
));
209 static int br_delbr(const char *br_name
)
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
));
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
));
238 Add a bridge with the name 'br_name'.
241 returns 1 if the bridge already exists
244 static int br_addbr(const char *br_name
)
247 unsigned long arg
[4];
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
));
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. */
266 wpa_printf(MSG_ERROR
, "VLAN: %s: BRCTL_ADD_BRIDGE "
268 __func__
, br_name
, strerror(errno
));
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
;
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 */
294 static int br_getnumports(const char *br_name
)
299 unsigned long arg
[4];
300 int ifindices
[MAX_BR_PORTS
];
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
));
309 arg
[0] = BRCTL_GET_PORT_LIST
;
310 arg
[1] = (unsigned long) ifindices
;
311 arg
[2] = MAX_BR_PORTS
;
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 "
321 __func__
, br_name
, strerror(errno
));
326 for (i
= 1; i
< MAX_BR_PORTS
; i
++) {
327 if (ifindices
[i
] > 0) {
337 static int vlan_rem(const char *if_name
)
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'",
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
));
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
));
373 Add a vlan interface with VLAN ID 'vid' and tagged interface
377 returns 1 if the interface already exists
380 static int vlan_add(const char *if_name
, int vid
)
383 struct vlan_ioctl_args if_request
;
385 wpa_printf(MSG_DEBUG
, "VLAN: vlan_add(if_name=%s, vid=%d)",
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'",
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
));
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",
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) {
419 wpa_printf(MSG_DEBUG
, "VLAN: vlan_add: "
420 "if_name %s exists already",
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: "
437 __func__
, if_request
.device1
, strerror(errno
));
447 static int vlan_set_name_type(unsigned int name_type
)
450 struct vlan_ioctl_args if_request
;
452 wpa_printf(MSG_DEBUG
, "VLAN: vlan_set_name_type(name_type=%u)",
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
));
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
));
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
);
487 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
489 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
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
;
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
);
535 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
536 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
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
);
560 hapd
->conf
->vlan
= vlan
->next
;
562 prev
->next
= vlan
->next
;
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
;
582 if (len
< sizeof(*ifi
))
587 nlmsg_len
= NLMSG_ALIGN(sizeof(struct ifinfomsg
));
589 attrlen
= h
->nlmsg_len
- nlmsg_len
;
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
;
604 os_memset(ifname
, 0, sizeof(ifname
));
606 if ((size_t) n
> sizeof(ifname
))
608 os_memcpy(ifname
, ((char *) attr
) + rta_len
, n
);
611 vlan_dellink(ifname
, hapd
);
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
)
625 struct sockaddr_nl from
;
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
);
634 if (errno
!= EINTR
&& errno
!= EAGAIN
)
635 wpa_printf(MSG_ERROR
, "VLAN: %s: recvfrom failed: %s",
636 __func__
, strerror(errno
));
640 h
= (struct nlmsghdr
*) buf
;
641 while (left
>= (int) sizeof(*h
)) {
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",
653 switch (h
->nlmsg_type
) {
655 vlan_read_ifnames(h
, plen
, 0, hapd
);
658 vlan_read_ifnames(h
, plen
, 1, hapd
);
662 len
= NLMSG_ALIGN(len
);
664 h
= (struct nlmsghdr
*) ((char *) h
+ len
);
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
));
684 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD
);
686 priv
->s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
688 wpa_printf(MSG_ERROR
, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
689 "NETLINK_ROUTE) failed: %s",
690 __func__
, strerror(errno
));
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
));
706 if (eloop_register_read_sock(priv
->s
, vlan_event_receive
, hapd
, NULL
))
717 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan
*priv
)
721 eloop_unregister_read_sock(priv
->s
);
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
)
733 if (dyn_vlan
== NULL
)
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");
753 static int vlan_dynamic_add(struct hostapd_data
*hapd
,
754 struct hostapd_vlan
*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",
767 #ifdef CONFIG_FULL_DYNAMIC_VLAN
768 ifconfig_up(vlan
->ifname
);
769 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
779 static void vlan_dynamic_remove(struct hostapd_data
*hapd
,
780 struct hostapd_vlan
*vlan
)
782 struct hostapd_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 "
791 vlan
->ifname
, strerror(errno
));
793 #ifdef CONFIG_FULL_DYNAMIC_VLAN
795 vlan_dellink(vlan
->ifname
, hapd
);
796 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
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
))
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
,
830 struct hostapd_vlan
*n
;
833 if (vlan
== NULL
|| vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
||
834 vlan
->vlan_id
!= VLAN_ID_WILDCARD
)
837 wpa_printf(MSG_DEBUG
, "VLAN: %s(vlan_id=%d ifname=%s)",
838 __func__
, vlan_id
, vlan
->ifname
);
839 ifname
= os_strdup(vlan
->ifname
);
842 pos
= os_strchr(ifname
, '#');
849 n
= os_zalloc(sizeof(*n
));
855 n
->vlan_id
= vlan_id
;
858 os_snprintf(n
->ifname
, sizeof(n
->ifname
), "%s%d%s", ifname
, vlan_id
,
862 if (hapd
->drv
.vlan_if_add(hapd
, n
->ifname
)) {
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 */
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
)
885 wpa_printf(MSG_DEBUG
, "VLAN: %s(vlan_id=%d)", __func__
, vlan_id
);
887 vlan
= hapd
->conf
->vlan
;
889 if (vlan
->vlan_id
== vlan_id
&& vlan
->dynamic_vlan
> 0) {
890 vlan
->dynamic_vlan
--;
899 if (vlan
->dynamic_vlan
== 0)
900 hapd
->drv
.vlan_if_remove(hapd
, vlan
->ifname
);