2 * hostapd / VLAN initialization
3 * Copyright 2003, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
20 #include "vlan_init.h"
23 #ifdef CONFIG_FULL_DYNAMIC_VLAN
26 #include <sys/ioctl.h>
27 #include <linux/sockios.h>
28 #include <linux/if_vlan.h>
29 typedef __uint64_t __u64
;
30 typedef __uint32_t __u32
;
31 typedef __int32_t __s32
;
32 typedef __uint16_t __u16
;
33 typedef __int16_t __s16
;
34 typedef __uint8_t __u8
;
35 #include <linux/if_bridge.h>
37 #include "priv_netlink.h"
41 struct full_dynamic_vlan
{
42 int s
; /* socket on which to listen for new/removed interfaces. */
46 static int ifconfig_helper(const char *if_name
, int up
)
51 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
52 perror("socket[AF_INET,SOCK_STREAM]");
56 os_memset(&ifr
, 0, sizeof(ifr
));
57 os_strlcpy(ifr
.ifr_name
, if_name
, IFNAMSIZ
);
59 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) != 0) {
60 perror("ioctl[SIOCGIFFLAGS]");
66 ifr
.ifr_flags
|= IFF_UP
;
68 ifr
.ifr_flags
&= ~IFF_UP
;
70 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
) != 0) {
71 perror("ioctl[SIOCSIFFLAGS]");
81 static int ifconfig_up(const char *if_name
)
83 return ifconfig_helper(if_name
, 1);
87 static int ifconfig_down(const char *if_name
)
89 return ifconfig_helper(if_name
, 0);
94 * These are only available in recent linux headers (without the leading
97 #define _GET_VLAN_REALDEV_NAME_CMD 8
98 #define _GET_VLAN_VID_CMD 9
100 /* This value should be 256 ONLY. If it is something else, then hostapd
101 * might crash!, as this value has been hard-coded in 2.4.x kernel
104 #define MAX_BR_PORTS 256
106 static int br_delif(const char *br_name
, const char *if_name
)
110 unsigned long args
[2];
113 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
114 perror("socket[AF_INET,SOCK_STREAM]");
118 if_index
= if_nametoindex(if_name
);
121 printf("Failure determining interface index for '%s'\n",
127 args
[0] = BRCTL_DEL_IF
;
130 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
131 ifr
.ifr_data
= (__caddr_t
) args
;
133 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0 && errno
!= EINVAL
) {
134 /* No error if interface already removed. */
135 perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
146 Add interface 'if_name' to the bridge 'br_name'
149 returns 1 if the interface is already part of the bridge
152 static int br_addif(const char *br_name
, const char *if_name
)
156 unsigned long args
[2];
159 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
160 perror("socket[AF_INET,SOCK_STREAM]");
164 if_index
= if_nametoindex(if_name
);
167 printf("Failure determining interface index for '%s'\n",
173 args
[0] = BRCTL_ADD_IF
;
176 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
177 ifr
.ifr_data
= (__caddr_t
) args
;
179 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
180 if (errno
== EBUSY
) {
181 /* The interface is already added. */
186 perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
196 static int br_delbr(const char *br_name
)
199 unsigned long arg
[2];
201 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
202 perror("socket[AF_INET,SOCK_STREAM]");
206 arg
[0] = BRCTL_DEL_BRIDGE
;
207 arg
[1] = (unsigned long) br_name
;
209 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0 && errno
!= ENXIO
) {
210 /* No error if bridge already removed. */
211 perror("ioctl[BRCTL_DEL_BRIDGE]");
222 Add a bridge with the name 'br_name'.
225 returns 1 if the bridge already exists
228 static int br_addbr(const char *br_name
)
231 unsigned long arg
[2];
233 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
234 perror("socket[AF_INET,SOCK_STREAM]");
238 arg
[0] = BRCTL_ADD_BRIDGE
;
239 arg
[1] = (unsigned long) br_name
;
241 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0) {
242 if (errno
== EEXIST
) {
243 /* The bridge is already added. */
247 perror("ioctl[BRCTL_ADD_BRIDGE]");
258 static int br_getnumports(const char *br_name
)
263 unsigned long arg
[4];
264 int ifindices
[MAX_BR_PORTS
];
267 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
268 perror("socket[AF_INET,SOCK_STREAM]");
272 arg
[0] = BRCTL_GET_PORT_LIST
;
273 arg
[1] = (unsigned long) ifindices
;
274 arg
[2] = MAX_BR_PORTS
;
277 os_memset(ifindices
, 0, sizeof(ifindices
));
278 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
279 ifr
.ifr_data
= (__caddr_t
) arg
;
281 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
282 perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
287 for (i
= 1; i
< MAX_BR_PORTS
; i
++) {
288 if (ifindices
[i
] > 0) {
298 static int vlan_rem(const char *if_name
)
301 struct vlan_ioctl_args if_request
;
303 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
304 fprintf(stderr
, "Interface name to long.\n");
308 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
309 perror("socket[AF_INET,SOCK_STREAM]");
313 os_memset(&if_request
, 0, sizeof(if_request
));
315 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
316 if_request
.cmd
= DEL_VLAN_CMD
;
318 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
319 perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
330 Add a vlan interface with VLAN ID 'vid' and tagged interface
334 returns 1 if the interface already exists
337 static int vlan_add(const char *if_name
, int vid
)
340 struct vlan_ioctl_args if_request
;
342 ifconfig_up(if_name
);
344 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
345 fprintf(stderr
, "Interface name to long.\n");
349 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
350 perror("socket[AF_INET,SOCK_STREAM]");
354 os_memset(&if_request
, 0, sizeof(if_request
));
356 /* Determine if a suitable vlan device already exists. */
358 os_snprintf(if_request
.device1
, sizeof(if_request
.device1
), "vlan%d",
361 if_request
.cmd
= _GET_VLAN_VID_CMD
;
363 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0) {
365 if (if_request
.u
.VID
== vid
) {
366 if_request
.cmd
= _GET_VLAN_REALDEV_NAME_CMD
;
368 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0 &&
369 os_strncmp(if_request
.u
.device2
, if_name
,
370 sizeof(if_request
.u
.device2
)) == 0) {
377 /* A suitable vlan device does not already exist, add one. */
379 os_memset(&if_request
, 0, sizeof(if_request
));
380 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
381 if_request
.u
.VID
= vid
;
382 if_request
.cmd
= ADD_VLAN_CMD
;
384 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
385 perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
395 static int vlan_set_name_type(unsigned int name_type
)
398 struct vlan_ioctl_args if_request
;
400 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
401 perror("socket[AF_INET,SOCK_STREAM]");
405 os_memset(&if_request
, 0, sizeof(if_request
));
407 if_request
.u
.name_type
= name_type
;
408 if_request
.cmd
= SET_VLAN_NAME_TYPE_CMD
;
409 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
410 perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
420 static void vlan_newlink(char *ifname
, struct hostapd_data
*hapd
)
422 char vlan_ifname
[IFNAMSIZ
];
423 char br_name
[IFNAMSIZ
];
424 struct hostapd_vlan
*vlan
= hapd
->conf
->vlan
;
425 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
428 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
430 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
433 if (!br_addbr(br_name
))
434 vlan
->clean
|= DVLAN_CLEAN_BR
;
436 ifconfig_up(br_name
);
438 if (tagged_interface
) {
440 if (!vlan_add(tagged_interface
, vlan
->vlan_id
))
441 vlan
->clean
|= DVLAN_CLEAN_VLAN
;
443 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
444 "vlan%d", vlan
->vlan_id
);
446 if (!br_addif(br_name
, vlan_ifname
))
447 vlan
->clean
|= DVLAN_CLEAN_VLAN_PORT
;
449 ifconfig_up(vlan_ifname
);
452 if (!br_addif(br_name
, ifname
))
453 vlan
->clean
|= DVLAN_CLEAN_WLAN_PORT
;
464 static void vlan_dellink(char *ifname
, struct hostapd_data
*hapd
)
466 char vlan_ifname
[IFNAMSIZ
];
467 char br_name
[IFNAMSIZ
];
468 struct hostapd_vlan
*first
, *prev
, *vlan
= hapd
->conf
->vlan
;
469 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
475 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
476 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
479 if (tagged_interface
) {
480 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
481 "vlan%d", vlan
->vlan_id
);
483 numports
= br_getnumports(br_name
);
485 br_delif(br_name
, vlan_ifname
);
487 vlan_rem(vlan_ifname
);
489 ifconfig_down(br_name
);
495 hapd
->conf
->vlan
= vlan
->next
;
497 prev
->next
= vlan
->next
;
510 vlan_read_ifnames(struct nlmsghdr
*h
, size_t len
, int del
,
511 struct hostapd_data
*hapd
)
513 struct ifinfomsg
*ifi
;
514 int attrlen
, nlmsg_len
, rta_len
;
517 if (len
< sizeof(*ifi
))
522 nlmsg_len
= NLMSG_ALIGN(sizeof(struct ifinfomsg
));
524 attrlen
= h
->nlmsg_len
- nlmsg_len
;
528 attr
= (struct rtattr
*) (((char *) ifi
) + nlmsg_len
);
530 rta_len
= RTA_ALIGN(sizeof(struct rtattr
));
531 while (RTA_OK(attr
, attrlen
)) {
532 char ifname
[IFNAMSIZ
+ 1];
534 if (attr
->rta_type
== IFLA_IFNAME
) {
535 int n
= attr
->rta_len
- rta_len
;
539 os_memset(ifname
, 0, sizeof(ifname
));
541 if ((size_t) n
> sizeof(ifname
))
543 os_memcpy(ifname
, ((char *) attr
) + rta_len
, n
);
546 vlan_dellink(ifname
, hapd
);
548 vlan_newlink(ifname
, hapd
);
551 attr
= RTA_NEXT(attr
, attrlen
);
556 static void vlan_event_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
560 struct sockaddr_nl from
;
563 struct hostapd_data
*hapd
= eloop_ctx
;
565 fromlen
= sizeof(from
);
566 left
= recvfrom(sock
, buf
, sizeof(buf
), MSG_DONTWAIT
,
567 (struct sockaddr
*) &from
, &fromlen
);
569 if (errno
!= EINTR
&& errno
!= EAGAIN
)
570 perror("recvfrom(netlink)");
574 h
= (struct nlmsghdr
*) buf
;
575 while (left
>= (int) sizeof(*h
)) {
579 plen
= len
- sizeof(*h
);
580 if (len
> left
|| plen
< 0) {
581 printf("Malformed netlink message: "
582 "len=%d left=%d plen=%d", len
, left
, plen
);
586 switch (h
->nlmsg_type
) {
588 vlan_read_ifnames(h
, plen
, 0, hapd
);
591 vlan_read_ifnames(h
, plen
, 1, hapd
);
595 len
= NLMSG_ALIGN(len
);
597 h
= (struct nlmsghdr
*) ((char *) h
+ len
);
601 printf("%d extra bytes in the end of netlink message",
607 static struct full_dynamic_vlan
*
608 full_dynamic_vlan_init(struct hostapd_data
*hapd
)
610 struct sockaddr_nl local
;
611 struct full_dynamic_vlan
*priv
;
613 priv
= os_zalloc(sizeof(*priv
));
617 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD
);
619 priv
->s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
621 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
626 os_memset(&local
, 0, sizeof(local
));
627 local
.nl_family
= AF_NETLINK
;
628 local
.nl_groups
= RTMGRP_LINK
;
629 if (bind(priv
->s
, (struct sockaddr
*) &local
, sizeof(local
)) < 0) {
630 perror("bind(netlink)");
636 if (eloop_register_read_sock(priv
->s
, vlan_event_receive
, hapd
, NULL
))
647 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan
*priv
)
651 eloop_unregister_read_sock(priv
->s
);
655 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
658 int vlan_setup_encryption_dyn(struct hostapd_data
*hapd
,
659 struct hostapd_ssid
*mssid
, const char *dyn_vlan
)
663 if (dyn_vlan
== NULL
)
666 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
667 * functions for setting up dynamic broadcast keys. */
668 for (i
= 0; i
< 4; i
++) {
669 if (mssid
->wep
.key
[i
] &&
670 hostapd_set_encryption(dyn_vlan
, hapd
, "WEP", NULL
,
671 i
, mssid
->wep
.key
[i
],
673 i
== mssid
->wep
.idx
)) {
674 printf("VLAN: Could not set WEP encryption for "
684 static int vlan_dynamic_add(struct hostapd_data
*hapd
,
685 struct hostapd_vlan
*vlan
)
688 if (vlan
->vlan_id
!= VLAN_ID_WILDCARD
&&
689 hostapd_if_add(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
, NULL
))
691 if (errno
!= EEXIST
) {
692 printf("Could not add VLAN iface: %s: %s\n",
693 vlan
->ifname
, strerror(errno
));
705 static void vlan_dynamic_remove(struct hostapd_data
*hapd
,
706 struct hostapd_vlan
*vlan
)
708 struct hostapd_vlan
*next
;
713 if (vlan
->vlan_id
!= VLAN_ID_WILDCARD
&&
714 hostapd_if_remove(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
,
716 printf("Could not remove VLAN iface: %s: %s\n",
717 vlan
->ifname
, strerror(errno
));
719 #ifdef CONFIG_FULL_DYNAMIC_VLAN
721 vlan_dellink(vlan
->ifname
, hapd
);
722 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
729 int vlan_init(struct hostapd_data
*hapd
)
731 if (vlan_dynamic_add(hapd
, hapd
->conf
->vlan
))
734 #ifdef CONFIG_FULL_DYNAMIC_VLAN
735 hapd
->full_dynamic_vlan
= full_dynamic_vlan_init(hapd
);
736 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
742 void vlan_deinit(struct hostapd_data
*hapd
)
744 vlan_dynamic_remove(hapd
, hapd
->conf
->vlan
);
746 #ifdef CONFIG_FULL_DYNAMIC_VLAN
747 full_dynamic_vlan_deinit(hapd
->full_dynamic_vlan
);
748 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
752 int vlan_reconfig(struct hostapd_data
*hapd
, struct hostapd_config
*oldconf
,
753 struct hostapd_bss_config
*oldbss
)
755 vlan_dynamic_remove(hapd
, oldbss
->vlan
);
756 if (vlan_dynamic_add(hapd
, hapd
->conf
->vlan
))
763 struct hostapd_vlan
* vlan_add_dynamic(struct hostapd_data
*hapd
,
764 struct hostapd_vlan
*vlan
,
767 struct hostapd_vlan
*n
;
770 if (vlan
== NULL
|| vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
||
771 vlan
->vlan_id
!= VLAN_ID_WILDCARD
)
774 ifname
= os_strdup(vlan
->ifname
);
777 pos
= os_strchr(ifname
, '#');
784 n
= os_zalloc(sizeof(*n
));
790 n
->vlan_id
= vlan_id
;
793 os_snprintf(n
->ifname
, sizeof(n
->ifname
), "%s%d%s", ifname
, vlan_id
,
797 if (hostapd_if_add(hapd
, HOSTAPD_IF_VLAN
, n
->ifname
, NULL
)) {
802 n
->next
= hapd
->conf
->vlan
;
803 hapd
->conf
->vlan
= n
;
809 int vlan_remove_dynamic(struct hostapd_data
*hapd
, int vlan_id
)
811 struct hostapd_vlan
*vlan
;
813 if (vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
)
816 vlan
= hapd
->conf
->vlan
;
818 if (vlan
->vlan_id
== vlan_id
&& vlan
->dynamic_vlan
> 0) {
819 vlan
->dynamic_vlan
--;
828 if (vlan
->dynamic_vlan
== 0)
829 hostapd_if_remove(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
, NULL
);