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 perror("socket[AF_INET,SOCK_STREAM]");
52 os_memset(&ifr
, 0, sizeof(ifr
));
53 os_strlcpy(ifr
.ifr_name
, if_name
, IFNAMSIZ
);
55 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) != 0) {
56 perror("ioctl[SIOCGIFFLAGS]");
62 ifr
.ifr_flags
|= IFF_UP
;
64 ifr
.ifr_flags
&= ~IFF_UP
;
66 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
) != 0) {
67 perror("ioctl[SIOCSIFFLAGS]");
77 static int ifconfig_up(const char *if_name
)
79 return ifconfig_helper(if_name
, 1);
83 static int ifconfig_down(const char *if_name
)
85 return ifconfig_helper(if_name
, 0);
90 * These are only available in recent linux headers (without the leading
93 #define _GET_VLAN_REALDEV_NAME_CMD 8
94 #define _GET_VLAN_VID_CMD 9
96 /* This value should be 256 ONLY. If it is something else, then hostapd
97 * might crash!, as this value has been hard-coded in 2.4.x kernel
100 #define MAX_BR_PORTS 256
102 static int br_delif(const char *br_name
, const char *if_name
)
106 unsigned long args
[2];
109 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
110 perror("socket[AF_INET,SOCK_STREAM]");
114 if_index
= if_nametoindex(if_name
);
117 printf("Failure determining interface index for '%s'\n",
123 args
[0] = BRCTL_DEL_IF
;
126 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
127 ifr
.ifr_data
= (__caddr_t
) args
;
129 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0 && errno
!= EINVAL
) {
130 /* No error if interface already removed. */
131 perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
142 Add interface 'if_name' to the bridge 'br_name'
145 returns 1 if the interface is already part of the bridge
148 static int br_addif(const char *br_name
, const char *if_name
)
152 unsigned long args
[2];
155 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
156 perror("socket[AF_INET,SOCK_STREAM]");
160 if_index
= if_nametoindex(if_name
);
163 printf("Failure determining interface index for '%s'\n",
169 args
[0] = BRCTL_ADD_IF
;
172 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
173 ifr
.ifr_data
= (__caddr_t
) args
;
175 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
176 if (errno
== EBUSY
) {
177 /* The interface is already added. */
182 perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
192 static int br_delbr(const char *br_name
)
195 unsigned long arg
[2];
197 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
198 perror("socket[AF_INET,SOCK_STREAM]");
202 arg
[0] = BRCTL_DEL_BRIDGE
;
203 arg
[1] = (unsigned long) br_name
;
205 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0 && errno
!= ENXIO
) {
206 /* No error if bridge already removed. */
207 perror("ioctl[BRCTL_DEL_BRIDGE]");
218 Add a bridge with the name 'br_name'.
221 returns 1 if the bridge already exists
224 static int br_addbr(const char *br_name
)
227 unsigned long arg
[2];
229 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
230 perror("socket[AF_INET,SOCK_STREAM]");
234 arg
[0] = BRCTL_ADD_BRIDGE
;
235 arg
[1] = (unsigned long) br_name
;
237 if (ioctl(fd
, SIOCGIFBR
, arg
) < 0) {
238 if (errno
== EEXIST
) {
239 /* The bridge is already added. */
243 perror("ioctl[BRCTL_ADD_BRIDGE]");
254 static int br_getnumports(const char *br_name
)
259 unsigned long arg
[4];
260 int ifindices
[MAX_BR_PORTS
];
263 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
264 perror("socket[AF_INET,SOCK_STREAM]");
268 arg
[0] = BRCTL_GET_PORT_LIST
;
269 arg
[1] = (unsigned long) ifindices
;
270 arg
[2] = MAX_BR_PORTS
;
273 os_memset(ifindices
, 0, sizeof(ifindices
));
274 os_strlcpy(ifr
.ifr_name
, br_name
, sizeof(ifr
.ifr_name
));
275 ifr
.ifr_data
= (__caddr_t
) arg
;
277 if (ioctl(fd
, SIOCDEVPRIVATE
, &ifr
) < 0) {
278 perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
283 for (i
= 1; i
< MAX_BR_PORTS
; i
++) {
284 if (ifindices
[i
] > 0) {
294 static int vlan_rem(const char *if_name
)
297 struct vlan_ioctl_args if_request
;
299 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
300 fprintf(stderr
, "Interface name to long.\n");
304 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
305 perror("socket[AF_INET,SOCK_STREAM]");
309 os_memset(&if_request
, 0, sizeof(if_request
));
311 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
312 if_request
.cmd
= DEL_VLAN_CMD
;
314 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
315 perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
326 Add a vlan interface with VLAN ID 'vid' and tagged interface
330 returns 1 if the interface already exists
333 static int vlan_add(const char *if_name
, int vid
)
336 struct vlan_ioctl_args if_request
;
338 ifconfig_up(if_name
);
340 if ((os_strlen(if_name
) + 1) > sizeof(if_request
.device1
)) {
341 fprintf(stderr
, "Interface name to long.\n");
345 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
346 perror("socket[AF_INET,SOCK_STREAM]");
350 os_memset(&if_request
, 0, sizeof(if_request
));
352 /* Determine if a suitable vlan device already exists. */
354 os_snprintf(if_request
.device1
, sizeof(if_request
.device1
), "vlan%d",
357 if_request
.cmd
= _GET_VLAN_VID_CMD
;
359 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0) {
361 if (if_request
.u
.VID
== vid
) {
362 if_request
.cmd
= _GET_VLAN_REALDEV_NAME_CMD
;
364 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) == 0 &&
365 os_strncmp(if_request
.u
.device2
, if_name
,
366 sizeof(if_request
.u
.device2
)) == 0) {
373 /* A suitable vlan device does not already exist, add one. */
375 os_memset(&if_request
, 0, sizeof(if_request
));
376 os_strlcpy(if_request
.device1
, if_name
, sizeof(if_request
.device1
));
377 if_request
.u
.VID
= vid
;
378 if_request
.cmd
= ADD_VLAN_CMD
;
380 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
381 perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
391 static int vlan_set_name_type(unsigned int name_type
)
394 struct vlan_ioctl_args if_request
;
396 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
397 perror("socket[AF_INET,SOCK_STREAM]");
401 os_memset(&if_request
, 0, sizeof(if_request
));
403 if_request
.u
.name_type
= name_type
;
404 if_request
.cmd
= SET_VLAN_NAME_TYPE_CMD
;
405 if (ioctl(fd
, SIOCSIFVLAN
, &if_request
) < 0) {
406 perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
416 static void vlan_newlink(char *ifname
, struct hostapd_data
*hapd
)
418 char vlan_ifname
[IFNAMSIZ
];
419 char br_name
[IFNAMSIZ
];
420 struct hostapd_vlan
*vlan
= hapd
->conf
->vlan
;
421 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
424 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
426 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
429 if (!br_addbr(br_name
))
430 vlan
->clean
|= DVLAN_CLEAN_BR
;
432 ifconfig_up(br_name
);
434 if (tagged_interface
) {
436 if (!vlan_add(tagged_interface
, vlan
->vlan_id
))
437 vlan
->clean
|= DVLAN_CLEAN_VLAN
;
439 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
440 "vlan%d", vlan
->vlan_id
);
442 if (!br_addif(br_name
, vlan_ifname
))
443 vlan
->clean
|= DVLAN_CLEAN_VLAN_PORT
;
445 ifconfig_up(vlan_ifname
);
448 if (!br_addif(br_name
, ifname
))
449 vlan
->clean
|= DVLAN_CLEAN_WLAN_PORT
;
460 static void vlan_dellink(char *ifname
, struct hostapd_data
*hapd
)
462 char vlan_ifname
[IFNAMSIZ
];
463 char br_name
[IFNAMSIZ
];
464 struct hostapd_vlan
*first
, *prev
, *vlan
= hapd
->conf
->vlan
;
465 char *tagged_interface
= hapd
->conf
->ssid
.vlan_tagged_interface
;
471 if (os_strcmp(ifname
, vlan
->ifname
) == 0) {
472 os_snprintf(br_name
, sizeof(br_name
), "brvlan%d",
475 if (tagged_interface
) {
476 os_snprintf(vlan_ifname
, sizeof(vlan_ifname
),
477 "vlan%d", vlan
->vlan_id
);
479 numports
= br_getnumports(br_name
);
481 br_delif(br_name
, vlan_ifname
);
483 vlan_rem(vlan_ifname
);
485 ifconfig_down(br_name
);
491 hapd
->conf
->vlan
= vlan
->next
;
493 prev
->next
= vlan
->next
;
506 vlan_read_ifnames(struct nlmsghdr
*h
, size_t len
, int del
,
507 struct hostapd_data
*hapd
)
509 struct ifinfomsg
*ifi
;
510 int attrlen
, nlmsg_len
, rta_len
;
513 if (len
< sizeof(*ifi
))
518 nlmsg_len
= NLMSG_ALIGN(sizeof(struct ifinfomsg
));
520 attrlen
= h
->nlmsg_len
- nlmsg_len
;
524 attr
= (struct rtattr
*) (((char *) ifi
) + nlmsg_len
);
526 rta_len
= RTA_ALIGN(sizeof(struct rtattr
));
527 while (RTA_OK(attr
, attrlen
)) {
528 char ifname
[IFNAMSIZ
+ 1];
530 if (attr
->rta_type
== IFLA_IFNAME
) {
531 int n
= attr
->rta_len
- rta_len
;
535 os_memset(ifname
, 0, sizeof(ifname
));
537 if ((size_t) n
> sizeof(ifname
))
539 os_memcpy(ifname
, ((char *) attr
) + rta_len
, n
);
542 vlan_dellink(ifname
, hapd
);
544 vlan_newlink(ifname
, hapd
);
547 attr
= RTA_NEXT(attr
, attrlen
);
552 static void vlan_event_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
556 struct sockaddr_nl from
;
559 struct hostapd_data
*hapd
= eloop_ctx
;
561 fromlen
= sizeof(from
);
562 left
= recvfrom(sock
, buf
, sizeof(buf
), MSG_DONTWAIT
,
563 (struct sockaddr
*) &from
, &fromlen
);
565 if (errno
!= EINTR
&& errno
!= EAGAIN
)
566 perror("recvfrom(netlink)");
570 h
= (struct nlmsghdr
*) buf
;
571 while (left
>= (int) sizeof(*h
)) {
575 plen
= len
- sizeof(*h
);
576 if (len
> left
|| plen
< 0) {
577 printf("Malformed netlink message: "
578 "len=%d left=%d plen=%d", len
, left
, plen
);
582 switch (h
->nlmsg_type
) {
584 vlan_read_ifnames(h
, plen
, 0, hapd
);
587 vlan_read_ifnames(h
, plen
, 1, hapd
);
591 len
= NLMSG_ALIGN(len
);
593 h
= (struct nlmsghdr
*) ((char *) h
+ len
);
597 printf("%d extra bytes in the end of netlink message",
603 static struct full_dynamic_vlan
*
604 full_dynamic_vlan_init(struct hostapd_data
*hapd
)
606 struct sockaddr_nl local
;
607 struct full_dynamic_vlan
*priv
;
609 priv
= os_zalloc(sizeof(*priv
));
613 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD
);
615 priv
->s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
617 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
622 os_memset(&local
, 0, sizeof(local
));
623 local
.nl_family
= AF_NETLINK
;
624 local
.nl_groups
= RTMGRP_LINK
;
625 if (bind(priv
->s
, (struct sockaddr
*) &local
, sizeof(local
)) < 0) {
626 perror("bind(netlink)");
632 if (eloop_register_read_sock(priv
->s
, vlan_event_receive
, hapd
, NULL
))
643 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan
*priv
)
647 eloop_unregister_read_sock(priv
->s
);
651 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
654 int vlan_setup_encryption_dyn(struct hostapd_data
*hapd
,
655 struct hostapd_ssid
*mssid
, const char *dyn_vlan
)
659 if (dyn_vlan
== NULL
)
662 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
663 * functions for setting up dynamic broadcast keys. */
664 for (i
= 0; i
< 4; i
++) {
665 if (mssid
->wep
.key
[i
] &&
666 hapd
->drv
.set_key(dyn_vlan
, hapd
, WPA_ALG_WEP
, NULL
, i
,
667 i
== mssid
->wep
.idx
, NULL
, 0,
668 mssid
->wep
.key
[i
], mssid
->wep
.len
[i
])) {
669 printf("VLAN: Could not set WEP encryption for "
679 static int vlan_dynamic_add(struct hostapd_data
*hapd
,
680 struct hostapd_vlan
*vlan
)
683 if (vlan
->vlan_id
!= VLAN_ID_WILDCARD
&&
684 hapd
->drv
.vlan_if_add(hapd
, vlan
->ifname
)) {
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 hapd
->drv
.vlan_if_remove(hapd
, vlan
->ifname
)) {
709 printf("Could not remove VLAN iface: %s: %s\n",
710 vlan
->ifname
, strerror(errno
));
712 #ifdef CONFIG_FULL_DYNAMIC_VLAN
714 vlan_dellink(vlan
->ifname
, hapd
);
715 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
722 int vlan_init(struct hostapd_data
*hapd
)
724 if (vlan_dynamic_add(hapd
, hapd
->conf
->vlan
))
727 #ifdef CONFIG_FULL_DYNAMIC_VLAN
728 hapd
->full_dynamic_vlan
= full_dynamic_vlan_init(hapd
);
729 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
735 void vlan_deinit(struct hostapd_data
*hapd
)
737 vlan_dynamic_remove(hapd
, hapd
->conf
->vlan
);
739 #ifdef CONFIG_FULL_DYNAMIC_VLAN
740 full_dynamic_vlan_deinit(hapd
->full_dynamic_vlan
);
741 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
745 struct hostapd_vlan
* vlan_add_dynamic(struct hostapd_data
*hapd
,
746 struct hostapd_vlan
*vlan
,
749 struct hostapd_vlan
*n
;
752 if (vlan
== NULL
|| vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
||
753 vlan
->vlan_id
!= VLAN_ID_WILDCARD
)
756 ifname
= os_strdup(vlan
->ifname
);
759 pos
= os_strchr(ifname
, '#');
766 n
= os_zalloc(sizeof(*n
));
772 n
->vlan_id
= vlan_id
;
775 os_snprintf(n
->ifname
, sizeof(n
->ifname
), "%s%d%s", ifname
, vlan_id
,
779 if (hapd
->drv
.vlan_if_add(hapd
, n
->ifname
)) {
784 n
->next
= hapd
->conf
->vlan
;
785 hapd
->conf
->vlan
= n
;
791 int vlan_remove_dynamic(struct hostapd_data
*hapd
, int vlan_id
)
793 struct hostapd_vlan
*vlan
;
795 if (vlan_id
<= 0 || vlan_id
> MAX_VLAN_ID
)
798 vlan
= hapd
->conf
->vlan
;
800 if (vlan
->vlan_id
== vlan_id
&& vlan
->dynamic_vlan
> 0) {
801 vlan
->dynamic_vlan
--;
810 if (vlan
->dynamic_vlan
== 0)
811 hapd
->drv
.vlan_if_remove(hapd
, vlan
->ifname
);