Sync usage with man page.
[netbsd-mini2440.git] / dist / wpa / hostapd / vlan_init.c
blob44f0dc68a2efc7e0e06ac14d4e5efa9319f5e106
1 /*
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
11 * license.
13 * See README and COPYING for more details.
16 #include "includes.h"
18 #include "hostapd.h"
19 #include "driver.h"
20 #include "vlan_init.h"
23 #ifdef CONFIG_FULL_DYNAMIC_VLAN
25 #include <net/if.h>
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"
38 #include "eloop.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)
48 int fd;
49 struct ifreq ifr;
51 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
52 perror("socket[AF_INET,SOCK_STREAM]");
53 return -1;
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]");
61 close(fd);
62 return -1;
65 if (up)
66 ifr.ifr_flags |= IFF_UP;
67 else
68 ifr.ifr_flags &= ~IFF_UP;
70 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
71 perror("ioctl[SIOCSIFFLAGS]");
72 close(fd);
73 return -1;
76 close(fd);
77 return 0;
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
95 * underscore).
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
102 * bridging code.
104 #define MAX_BR_PORTS 256
106 static int br_delif(const char *br_name, const char *if_name)
108 int fd;
109 struct ifreq ifr;
110 unsigned long args[2];
111 int if_index;
113 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
114 perror("socket[AF_INET,SOCK_STREAM]");
115 return -1;
118 if_index = if_nametoindex(if_name);
120 if (if_index == 0) {
121 printf("Failure determining interface index for '%s'\n",
122 if_name);
123 close(fd);
124 return -1;
127 args[0] = BRCTL_DEL_IF;
128 args[1] = if_index;
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]");
136 close(fd);
137 return -1;
140 close(fd);
141 return 0;
146 Add interface 'if_name' to the bridge 'br_name'
148 returns -1 on error
149 returns 1 if the interface is already part of the bridge
150 returns 0 otherwise
152 static int br_addif(const char *br_name, const char *if_name)
154 int fd;
155 struct ifreq ifr;
156 unsigned long args[2];
157 int if_index;
159 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
160 perror("socket[AF_INET,SOCK_STREAM]");
161 return -1;
164 if_index = if_nametoindex(if_name);
166 if (if_index == 0) {
167 printf("Failure determining interface index for '%s'\n",
168 if_name);
169 close(fd);
170 return -1;
173 args[0] = BRCTL_ADD_IF;
174 args[1] = if_index;
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. */
182 close(fd);
183 return 1;
186 perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
187 close(fd);
188 return -1;
191 close(fd);
192 return 0;
196 static int br_delbr(const char *br_name)
198 int fd;
199 unsigned long arg[2];
201 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
202 perror("socket[AF_INET,SOCK_STREAM]");
203 return -1;
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]");
212 close(fd);
213 return -1;
216 close(fd);
217 return 0;
222 Add a bridge with the name 'br_name'.
224 returns -1 on error
225 returns 1 if the bridge already exists
226 returns 0 otherwise
228 static int br_addbr(const char *br_name)
230 int fd;
231 unsigned long arg[2];
233 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
234 perror("socket[AF_INET,SOCK_STREAM]");
235 return -1;
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. */
244 close(fd);
245 return 1;
246 } else {
247 perror("ioctl[BRCTL_ADD_BRIDGE]");
248 close(fd);
249 return -1;
253 close(fd);
254 return 0;
258 static int br_getnumports(const char *br_name)
260 int fd;
261 int i;
262 int port_cnt = 0;
263 unsigned long arg[4];
264 int ifindices[MAX_BR_PORTS];
265 struct ifreq ifr;
267 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
268 perror("socket[AF_INET,SOCK_STREAM]");
269 return -1;
272 arg[0] = BRCTL_GET_PORT_LIST;
273 arg[1] = (unsigned long) ifindices;
274 arg[2] = MAX_BR_PORTS;
275 arg[3] = 0;
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]");
283 close(fd);
284 return -1;
287 for (i = 1; i < MAX_BR_PORTS; i++) {
288 if (ifindices[i] > 0) {
289 port_cnt++;
293 close(fd);
294 return port_cnt;
298 static int vlan_rem(const char *if_name)
300 int fd;
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");
305 return -1;
308 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
309 perror("socket[AF_INET,SOCK_STREAM]");
310 return -1;
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]");
320 close(fd);
321 return -1;
324 close(fd);
325 return 0;
330 Add a vlan interface with VLAN ID 'vid' and tagged interface
331 'if_name'.
333 returns -1 on error
334 returns 1 if the interface already exists
335 returns 0 otherwise
337 static int vlan_add(const char *if_name, int vid)
339 int fd;
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");
346 return -1;
349 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
350 perror("socket[AF_INET,SOCK_STREAM]");
351 return -1;
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",
359 vid);
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) {
371 close(fd);
372 return 1;
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]");
386 close(fd);
387 return -1;
390 close(fd);
391 return 0;
395 static int vlan_set_name_type(unsigned int name_type)
397 int fd;
398 struct vlan_ioctl_args if_request;
400 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
401 perror("socket[AF_INET,SOCK_STREAM]");
402 return -1;
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]");
411 close(fd);
412 return -1;
415 close(fd);
416 return 0;
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;
427 while (vlan) {
428 if (os_strcmp(ifname, vlan->ifname) == 0) {
430 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
431 vlan->vlan_id);
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;
455 ifconfig_up(ifname);
457 break;
459 vlan = vlan->next;
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;
470 int numports;
472 first = prev = vlan;
474 while (vlan) {
475 if (os_strcmp(ifname, vlan->ifname) == 0) {
476 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
477 vlan->vlan_id);
479 if (tagged_interface) {
480 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
481 "vlan%d", vlan->vlan_id);
483 numports = br_getnumports(br_name);
484 if (numports == 1) {
485 br_delif(br_name, vlan_ifname);
487 vlan_rem(vlan_ifname);
489 ifconfig_down(br_name);
490 br_delbr(br_name);
494 if (vlan == first) {
495 hapd->conf->vlan = vlan->next;
496 } else {
497 prev->next = vlan->next;
499 os_free(vlan);
501 break;
503 prev = vlan;
504 vlan = vlan->next;
509 static void
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;
515 struct rtattr *attr;
517 if (len < sizeof(*ifi))
518 return;
520 ifi = NLMSG_DATA(h);
522 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
524 attrlen = h->nlmsg_len - nlmsg_len;
525 if (attrlen < 0)
526 return;
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;
536 if (n < 0)
537 break;
539 os_memset(ifname, 0, sizeof(ifname));
541 if ((size_t) n > sizeof(ifname))
542 n = sizeof(ifname);
543 os_memcpy(ifname, ((char *) attr) + rta_len, n);
545 if (del)
546 vlan_dellink(ifname, hapd);
547 else
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)
558 char buf[8192];
559 int left;
560 struct sockaddr_nl from;
561 socklen_t fromlen;
562 struct nlmsghdr *h;
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);
568 if (left < 0) {
569 if (errno != EINTR && errno != EAGAIN)
570 perror("recvfrom(netlink)");
571 return;
574 h = (struct nlmsghdr *) buf;
575 while (left >= (int) sizeof(*h)) {
576 int len, plen;
578 len = h->nlmsg_len;
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);
583 break;
586 switch (h->nlmsg_type) {
587 case RTM_NEWLINK:
588 vlan_read_ifnames(h, plen, 0, hapd);
589 break;
590 case RTM_DELLINK:
591 vlan_read_ifnames(h, plen, 1, hapd);
592 break;
595 len = NLMSG_ALIGN(len);
596 left -= len;
597 h = (struct nlmsghdr *) ((char *) h + len);
600 if (left > 0) {
601 printf("%d extra bytes in the end of netlink message",
602 left);
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));
614 if (priv == NULL)
615 return NULL;
617 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
619 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
620 if (priv->s < 0) {
621 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
622 os_free(priv);
623 return NULL;
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)");
631 close(priv->s);
632 os_free(priv);
633 return NULL;
636 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
638 close(priv->s);
639 os_free(priv);
640 return NULL;
643 return priv;
647 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
649 if (priv == NULL)
650 return;
651 eloop_unregister_read_sock(priv->s);
652 close(priv->s);
653 os_free(priv);
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)
661 int i;
663 if (dyn_vlan == NULL)
664 return 0;
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],
672 mssid->wep.len[i],
673 i == mssid->wep.idx)) {
674 printf("VLAN: Could not set WEP encryption for "
675 "dynamic VLAN.\n");
676 return -1;
680 return 0;
684 static int vlan_dynamic_add(struct hostapd_data *hapd,
685 struct hostapd_vlan *vlan)
687 while (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));
694 return -1;
698 vlan = vlan->next;
701 return 0;
705 static void vlan_dynamic_remove(struct hostapd_data *hapd,
706 struct hostapd_vlan *vlan)
708 struct hostapd_vlan *next;
710 while (vlan) {
711 next = vlan->next;
713 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
714 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
715 NULL)) {
716 printf("Could not remove VLAN iface: %s: %s\n",
717 vlan->ifname, strerror(errno));
719 #ifdef CONFIG_FULL_DYNAMIC_VLAN
720 if (vlan->clean)
721 vlan_dellink(vlan->ifname, hapd);
722 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
724 vlan = next;
729 int vlan_init(struct hostapd_data *hapd)
731 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
732 return -1;
734 #ifdef CONFIG_FULL_DYNAMIC_VLAN
735 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
736 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
738 return 0;
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))
757 return -1;
759 return 0;
763 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
764 struct hostapd_vlan *vlan,
765 int vlan_id)
767 struct hostapd_vlan *n;
768 char *ifname, *pos;
770 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
771 vlan->vlan_id != VLAN_ID_WILDCARD)
772 return NULL;
774 ifname = os_strdup(vlan->ifname);
775 if (ifname == NULL)
776 return NULL;
777 pos = os_strchr(ifname, '#');
778 if (pos == NULL) {
779 os_free(ifname);
780 return NULL;
782 *pos++ = '\0';
784 n = os_zalloc(sizeof(*n));
785 if (n == NULL) {
786 os_free(ifname);
787 return NULL;
790 n->vlan_id = vlan_id;
791 n->dynamic_vlan = 1;
793 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
794 pos);
795 os_free(ifname);
797 if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
798 os_free(n);
799 return NULL;
802 n->next = hapd->conf->vlan;
803 hapd->conf->vlan = n;
805 return 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)
814 return 1;
816 vlan = hapd->conf->vlan;
817 while (vlan) {
818 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
819 vlan->dynamic_vlan--;
820 break;
822 vlan = vlan->next;
825 if (vlan == NULL)
826 return 1;
828 if (vlan->dynamic_vlan == 0)
829 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
831 return 0;