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 memset(&ifr, 0, sizeof(ifr));
57 strncpy(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 strncpy(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 strncpy(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 memset(ifindices, 0, sizeof(ifindices));
278 strncpy(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 ((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 memset(&if_request, 0, sizeof(if_request));
315 strcpy(if_request.device1, if_name);
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 ((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 memset(&if_request, 0, sizeof(if_request));
356 /* Determine if a suitable vlan device already exists. */
358 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 && 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 memset(&if_request, 0, sizeof(if_request));
380 strcpy(if_request.device1, if_name);
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 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 (strcmp(ifname, vlan->ifname) == 0) {
430 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 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 (strcmp(ifname, vlan->ifname) == 0) {
476 snprintf(br_name, sizeof(br_name), "brvlan%d",
479 if (tagged_interface) {
480 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 memset(ifname, 0, sizeof(ifname));
541 if ((size_t) n > sizeof(ifname))
543 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 = malloc(sizeof(*priv));
618 memset(priv, 0, sizeof(*priv));
620 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
622 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
624 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
629 memset(&local, 0, sizeof(local));
630 local.nl_family = AF_NETLINK;
631 local.nl_groups = RTMGRP_LINK;
632 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
633 perror("bind(netlink)");
639 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
650 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
654 eloop_unregister_read_sock(priv->s);
658 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
661 int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
662 struct hostapd_ssid *mssid, const char *dyn_vlan)
666 if (dyn_vlan == NULL)
669 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
670 * functions for setting up dynamic broadcast keys. */
671 for (i = 0; i < 4; i++) {
672 if (mssid->wep.key[i] &&
673 hostapd_set_encryption(dyn_vlan, hapd, "WEP", NULL,
674 i, mssid->wep.key[i],
676 i == mssid->wep.idx)) {
677 printf("VLAN: Could not set WEP encryption for "
687 static int vlan_dynamic_add(struct hostapd_data *hapd,
688 struct hostapd_vlan *vlan)
691 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
692 hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
694 if (errno != EEXIST) {
695 printf("Could not add VLAN iface: %s: %s\n",
696 vlan->ifname, strerror(errno));
708 static void vlan_dynamic_remove(struct hostapd_data *hapd,
709 struct hostapd_vlan *vlan)
711 struct hostapd_vlan *next;
716 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
717 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
719 printf("Could not remove VLAN iface: %s: %s\n",
720 vlan->ifname, strerror(errno));
722 #ifdef CONFIG_FULL_DYNAMIC_VLAN
724 vlan_dellink(vlan->ifname, hapd);
725 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
732 int vlan_init(struct hostapd_data *hapd)
734 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
737 #ifdef CONFIG_FULL_DYNAMIC_VLAN
738 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
739 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
745 void vlan_deinit(struct hostapd_data *hapd)
747 vlan_dynamic_remove(hapd, hapd->conf->vlan);
749 #ifdef CONFIG_FULL_DYNAMIC_VLAN
750 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
751 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
755 int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
756 struct hostapd_bss_config *oldbss)
758 vlan_dynamic_remove(hapd, oldbss->vlan);
759 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
766 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
767 struct hostapd_vlan *vlan,
770 struct hostapd_vlan *n;
773 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
774 vlan->vlan_id != VLAN_ID_WILDCARD)
777 ifname = strdup(vlan->ifname);
780 pos = strchr(ifname, '#');
787 n = malloc(sizeof(*n));
793 memset(n, 0, sizeof(*n));
794 n->vlan_id = vlan_id;
797 snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, pos);
800 if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
805 n->next = hapd->conf->vlan;
806 hapd->conf->vlan = n;
812 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
814 struct hostapd_vlan *vlan;
816 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
819 vlan = hapd->conf->vlan;
821 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
822 vlan->dynamic_vlan--;
831 if (vlan->dynamic_vlan == 0)
832 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);