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 #include <linux/if_bridge.h>
31 #include "priv_netlink.h"
35 struct full_dynamic_vlan
{
36 int s
; /* socket on which to listen for new/removed interfaces. */
40 static int ifconfig_helper(const char *if_name
, int up
)
45 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
46 perror("socket[AF_INET,SOCK_STREAM]");
50 os_memset(&ifr
, 0, sizeof(ifr
));
51 os_strlcpy(ifr
.ifr_name
, if_name
, IFNAMSIZ
);
53 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) != 0) {
54 perror("ioctl[SIOCGIFFLAGS]");
60 ifr
.ifr_flags
|= IFF_UP
;
62 ifr
.ifr_flags
&= ~IFF_UP
;
64 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
) != 0) {
65 perror("ioctl[SIOCSIFFLAGS]");
75 static int ifconfig_up(const char *if_name
)
77 return ifconfig_helper(if_name
, 1);
81 static int ifconfig_down(const char *if_name
)
83 return ifconfig_helper(if_name
, 0);
88 * These are only available in recent linux headers (without the leading
91 #define _GET_VLAN_REALDEV_NAME_CMD 8
92 #define _GET_VLAN_VID_CMD 9
94 /* This value should be 256 ONLY. If it is something else, then hostapd
95 * might crash!, as this value has been hard-coded in 2.4.x kernel
98 #define MAX_BR_PORTS 256
100 static int br_delif(const char *br_name
, const char *if_name
)
104 unsigned long args
[2];
107 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
108 perror("socket[AF_INET,SOCK_STREAM]");
112 if_index
= if_nametoindex(if_name
);
115 printf("Failure determining interface index for '%s'\n",
121 args
[0] = BRCTL_DEL_IF
;
124 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
125 ifr
.ifr_data
= (__caddr_t
) args
;
127 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0 && errno
!= EINVAL
) {
128 /* No error if interface already removed. */
129 perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
140 Add interface 'if_name' to the bridge 'br_name'
143 returns 1 if the interface is already part of the bridge
146 static int br_addif(const char *br_name
, const char *if_name
)
150 unsigned long args
[2];
153 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
154 perror("socket[AF_INET,SOCK_STREAM]");
158 if_index
= if_nametoindex(if_name
);
161 printf("Failure determining interface index for '%s'\n",
167 args
[0] = BRCTL_ADD_IF
;
170 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
171 ifr
.ifr_data
= (__caddr_t
) args
;
173 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
174 if (errno
== EBUSY
) {
175 /* The interface is already added. */
180 perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
190 static int br_delbr(const char *br_name
)
193 unsigned long arg
[2];
195 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
196 perror("socket[AF_INET,SOCK_STREAM]");
200 arg
[0] = BRCTL_DEL_BRIDGE
;
201 arg
[1] = (unsigned long) br_name
;
203 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0 && errno
!= ENXIO
) {
204 /* No error if bridge already removed. */
205 perror("ioctl[BRCTL_DEL_BRIDGE]");
216 Add a bridge with the name 'br_name'.
219 returns 1 if the bridge already exists
222 static int br_addbr(const char *br_name
)
225 unsigned long arg
[2];
227 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
228 perror("socket[AF_INET,SOCK_STREAM]");
232 arg
[0] = BRCTL_ADD_BRIDGE
;
233 arg
[1] = (unsigned long) br_name
;
235 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0) {
236 if (errno
== EEXIST
) {
237 /* The bridge is already added. */
241 perror("ioctl[BRCTL_ADD_BRIDGE]");
252 static int br_getnumports(const char *br_name
)
257 unsigned long arg
[4];
258 int ifindices
[MAX_BR_PORTS
];
261 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
262 perror("socket[AF_INET,SOCK_STREAM]");
266 arg
[0] = BRCTL_GET_PORT_LIST
;
267 arg
[1] = (unsigned long) ifindices
;
268 arg
[2] = MAX_BR_PORTS
;
271 os_memset(ifindices
, 0, sizeof(ifindices
));
272 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
273 ifr
.ifr_data
= (__caddr_t
) arg
;
275 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
276 perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
281 for (i
= 1; i
< MAX_BR_PORTS
; i
++) {
282 if (ifindices
[i
] > 0) {
292 static int vlan_rem(const char *if_name
)
295 struct vlan_ioctl_args if_request
;
297 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
298 fprintf(stderr
, "Interface name to long.\n");
302 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
303 perror("socket[AF_INET,SOCK_STREAM]");
307 os_memset(&if_request
, 0, sizeof(if_request
));
309 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
310 if_request
.cmd
= DEL_VLAN_CMD
;
312 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
313 perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
324 Add a vlan interface with VLAN ID 'vid' and tagged interface
328 returns 1 if the interface already exists
331 static int vlan_add(const char *if_name
, int vid
)
334 struct vlan_ioctl_args if_request
;
336 ifconfig_up(if_name
);
338 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
339 fprintf(stderr
, "Interface name to long.\n");
343 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
344 perror("socket[AF_INET,SOCK_STREAM]");
348 os_memset(&if_request
, 0, sizeof(if_request
));
350 /* Determine if a suitable vlan device already exists. */
352 os_snprintf(if_request
.device1
, sizeof(if_request
.device1
), "vlan%d",
355 if_request
.cmd
= _GET_VLAN_VID_CMD
;
357 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0) {
359 if (if_request
.u
.VID
== vid
) {
360 if_request
.cmd
= _GET_VLAN_REALDEV_NAME_CMD
;
362 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0 &&
363 os_strncmp(if_request
.u
.device2
, if_name
,
364 sizeof(if_request
.u
.device2
)) == 0) {
371 /* A suitable vlan device does not already exist, add one. */
373 os_memset(&if_request
, 0, sizeof(if_request
));
374 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
375 if_request
.u
.VID
= vid
;
376 if_request
.cmd
= ADD_VLAN_CMD
;
378 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
379 perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
389 static int vlan_set_name_type(unsigned int name_type
)
392 struct vlan_ioctl_args if_request
;
394 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
395 perror("socket[AF_INET,SOCK_STREAM]");
399 os_memset(&if_request
, 0, sizeof(if_request
));
401 if_request
.u
.name_type
= name_type
;
402 if_request
.cmd
= SET_VLAN_NAME_TYPE_CMD
;
403 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
404 perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
414 static void vlan_newlink(char *ifname
, struct hostapd_data
*hapd
)
416 char vlan_ifname
[IFNAMSIZ
];
417 char br_name
[IFNAMSIZ
];
418 struct hostapd_vlan
*vlan
= hapd
->conf
->vlan
;
419 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
422 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
424 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
427 if (!br_addbr(br_name
))
428 vlan
->clean
|= DVLAN_CLEAN_BR
;
430 ifconfig_up(br_name
);
432 if (tagged_interface
) {
434 if (!vlan_add(tagged_interface
, vlan
->vlan_id
))
435 vlan
->clean
|= DVLAN_CLEAN_VLAN
;
437 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
438 "vlan%d", vlan
->vlan_id
);
440 if (!br_addif(br_name
, vlan_ifname
))
441 vlan
->clean
|= DVLAN_CLEAN_VLAN_PORT
;
443 ifconfig_up(vlan_ifname
);
446 if (!br_addif(br_name
, ifname
))
447 vlan
->clean
|= DVLAN_CLEAN_WLAN_PORT
;
458 static void vlan_dellink(char *ifname
, struct hostapd_data
*hapd
)
460 char vlan_ifname
[IFNAMSIZ
];
461 char br_name
[IFNAMSIZ
];
462 struct hostapd_vlan
*first
, *prev
, *vlan
= hapd
->conf
->vlan
;
463 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
469 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
470 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
473 if (tagged_interface
) {
474 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
475 "vlan%d", vlan
->vlan_id
);
477 numports
= br_getnumports(br_name
);
479 br_delif(br_name
, vlan_ifname
);
481 vlan_rem(vlan_ifname
);
483 ifconfig_down(br_name
);
489 hapd
->conf
->vlan
= vlan
->next
;
491 prev
->next
= vlan
->next
;
504 vlan_read_ifnames(struct nlmsghdr
*h
, size_t len
, int del
,
505 struct hostapd_data
*hapd
)
507 struct ifinfomsg
*ifi
;
508 int attrlen
, nlmsg_len
, rta_len
;
511 if (len
< sizeof(*ifi
))
516 nlmsg_len
= NLMSG_ALIGN(sizeof(struct ifinfomsg
));
518 attrlen
= h
->nlmsg_len
- nlmsg_len
;
522 attr
= (struct rtattr
*) (((char *) ifi
) + nlmsg_len
);
524 rta_len
= RTA_ALIGN(sizeof(struct rtattr
));
525 while (RTA_OK(attr
, attrlen
)) {
526 char ifname
[IFNAMSIZ
+ 1];
528 if (attr
->rta_type
== IFLA_IFNAME
) {
529 int n
= attr
->rta_len
- rta_len
;
533 os_memset(ifname
, 0, sizeof(ifname
));
535 if ((size_t) n
> sizeof(ifname
))
537 os_memcpy(ifname
, ((char *) attr
) + rta_len
, n
);
540 vlan_dellink(ifname
, hapd
);
542 vlan_newlink(ifname
, hapd
);
545 attr
= RTA_NEXT(attr
, attrlen
);
550 static void vlan_event_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
554 struct sockaddr_nl from
;
557 struct hostapd_data
*hapd
= eloop_ctx
;
559 fromlen
= sizeof(from
);
560 left
= recvfrom(sock
, buf
, sizeof(buf
), MSG_DONTWAIT
,
561 (struct sockaddr
*) &from
, &fromlen
);
563 if (errno
!= EINTR
&& errno
!= EAGAIN
)
564 perror("recvfrom(netlink)");
568 h
= (struct nlmsghdr
*) buf
;
569 while (left
>= (int) sizeof(*h
)) {
573 plen
= len
- sizeof(*h
);
574 if (len
> left
|| plen
< 0) {
575 printf("Malformed netlink message: "
576 "len=%d left=%d plen=%d", len
, left
, plen
);
580 switch (h
->nlmsg_type
) {
582 vlan_read_ifnames(h
, plen
, 0, hapd
);
585 vlan_read_ifnames(h
, plen
, 1, hapd
);
589 len
= NLMSG_ALIGN(len
);
591 h
= (struct nlmsghdr
*) ((char *) h
+ len
);
595 printf("%d extra bytes in the end of netlink message",
601 static struct full_dynamic_vlan
*
602 full_dynamic_vlan_init(struct hostapd_data
*hapd
)
604 struct sockaddr_nl local
;
605 struct full_dynamic_vlan
*priv
;
607 priv
= os_zalloc(sizeof(*priv
));
611 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD
);
613 priv
->s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
615 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
620 os_memset(&local
, 0, sizeof(local
));
621 local
.nl_family
= AF_NETLINK
;
622 local
.nl_groups
= RTMGRP_LINK
;
623 if (bind(priv
->s
, (struct sockaddr
*) &local
, sizeof(local
)) < 0) {
624 perror("bind(netlink)");
630 if (eloop_register_read_sock(priv
->s
, vlan_event_receive
, hapd
, NULL
))
641 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan
*priv
)
645 eloop_unregister_read_sock(priv
->s
);
649 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
652 int vlan_setup_encryption_dyn(struct hostapd_data
*hapd
,
653 struct hostapd_ssid
*mssid
, const char *dyn_vlan
)
657 if (dyn_vlan
== NULL
)
660 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
661 * functions for setting up dynamic broadcast keys. */
662 for (i
= 0; i
< 4; i
++) {
663 if (mssid
->wep
.key
[i
] &&
664 hostapd_set_encryption(dyn_vlan
, hapd
, "WEP", NULL
,
665 i
, mssid
->wep
.key
[i
],
667 i
== mssid
->wep
.idx
)) {
668 printf("VLAN: Could not set WEP encryption for "
678 static int vlan_dynamic_add(struct hostapd_data
*hapd
,
679 struct hostapd_vlan
*vlan
)
682 if (vlan
->vlan_id
!= VLAN_ID_WILDCARD
&&
683 hostapd_if_add(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
, NULL
))
685 if (errno
!= EEXIST
) {
686 printf("Could not add VLAN iface: %s: %s\n",
687 vlan
->ifname
, strerror(errno
));
699 static void vlan_dynamic_remove(struct hostapd_data
*hapd
,
700 struct hostapd_vlan
*vlan
)
702 struct hostapd_vlan
*next
;
707 if (vlan
->vlan_id
!= VLAN_ID_WILDCARD
&&
708 hostapd_if_remove(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
,
710 printf("Could not remove VLAN iface: %s: %s\n",
711 vlan
->ifname
, strerror(errno
));
713 #ifdef CONFIG_FULL_DYNAMIC_VLAN
715 vlan_dellink(vlan
->ifname
, hapd
);
716 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
723 int vlan_init(struct hostapd_data
*hapd
)
725 if (vlan_dynamic_add(hapd
, hapd
->conf
->vlan
))
728 #ifdef CONFIG_FULL_DYNAMIC_VLAN
729 hapd
->full_dynamic_vlan
= full_dynamic_vlan_init(hapd
);
730 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
736 void vlan_deinit(struct hostapd_data
*hapd
)
738 vlan_dynamic_remove(hapd
, hapd
->conf
->vlan
);
740 #ifdef CONFIG_FULL_DYNAMIC_VLAN
741 full_dynamic_vlan_deinit(hapd
->full_dynamic_vlan
);
742 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
746 int vlan_reconfig(struct hostapd_data
*hapd
, struct hostapd_config
*oldconf
,
747 struct hostapd_bss_config
*oldbss
)
749 vlan_dynamic_remove(hapd
, oldbss
->vlan
);
750 if (vlan_dynamic_add(hapd
, hapd
->conf
->vlan
))
757 struct hostapd_vlan
* vlan_add_dynamic(struct hostapd_data
*hapd
,
758 struct hostapd_vlan
*vlan
,
761 struct hostapd_vlan
*n
;
764 if (vlan
== NULL
|| vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
||
765 vlan
->vlan_id
!= VLAN_ID_WILDCARD
)
768 ifname
= os_strdup(vlan
->ifname
);
771 pos
= os_strchr(ifname
, '#');
778 n
= os_zalloc(sizeof(*n
));
784 n
->vlan_id
= vlan_id
;
787 os_snprintf(n
->ifname
, sizeof(n
->ifname
), "%s%d%s", ifname
, vlan_id
,
791 if (hostapd_if_add(hapd
, HOSTAPD_IF_VLAN
, n
->ifname
, NULL
)) {
796 n
->next
= hapd
->conf
->vlan
;
797 hapd
->conf
->vlan
= n
;
803 int vlan_remove_dynamic(struct hostapd_data
*hapd
, int vlan_id
)
805 struct hostapd_vlan
*vlan
;
807 if (vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
)
810 vlan
= hapd
->conf
->vlan
;
812 if (vlan
->vlan_id
== vlan_id
&& vlan
->dynamic_vlan
> 0) {
813 vlan
->dynamic_vlan
--;
822 if (vlan
->dynamic_vlan
== 0)
823 hostapd_if_remove(hapd
, HOSTAPD_IF_VLAN
, vlan
->ifname
, NULL
);