Add a new option -s. With this option pkg_search(1) will display the description
[dragonfly.git] / contrib / hostapd-0.5.8 / vlan_init.c
blobd546c74afdc69e5649f5a3f1795a29916bc5f496
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 memset(&ifr, 0, sizeof(ifr));
57 strncpy(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 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]");
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 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. */
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 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]");
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 ((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 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]");
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 ((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 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",
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 && 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 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]");
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 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 (strcmp(ifname, vlan->ifname) == 0) {
430 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 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 (strcmp(ifname, vlan->ifname) == 0) {
476 snprintf(br_name, sizeof(br_name), "brvlan%d",
477 vlan->vlan_id);
479 if (tagged_interface) {
480 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 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 memset(ifname, 0, sizeof(ifname));
541 if ((size_t) n > sizeof(ifname))
542 n = sizeof(ifname);
543 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 = malloc(sizeof(*priv));
615 if (priv == NULL)
616 return NULL;
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);
623 if (priv->s < 0) {
624 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
625 free(priv);
626 return NULL;
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)");
634 close(priv->s);
635 free(priv);
636 return NULL;
639 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
641 close(priv->s);
642 free(priv);
643 return NULL;
646 return priv;
650 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
652 if (priv == NULL)
653 return;
654 eloop_unregister_read_sock(priv->s);
655 close(priv->s);
656 free(priv);
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)
664 int i;
666 if (dyn_vlan == NULL)
667 return 0;
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],
675 mssid->wep.len[i],
676 i == mssid->wep.idx)) {
677 printf("VLAN: Could not set WEP encryption for "
678 "dynamic VLAN.\n");
679 return -1;
683 return 0;
687 static int vlan_dynamic_add(struct hostapd_data *hapd,
688 struct hostapd_vlan *vlan)
690 while (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));
697 return -1;
701 vlan = vlan->next;
704 return 0;
708 static void vlan_dynamic_remove(struct hostapd_data *hapd,
709 struct hostapd_vlan *vlan)
711 struct hostapd_vlan *next;
713 while (vlan) {
714 next = vlan->next;
716 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
717 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
718 NULL)) {
719 printf("Could not remove VLAN iface: %s: %s\n",
720 vlan->ifname, strerror(errno));
722 #ifdef CONFIG_FULL_DYNAMIC_VLAN
723 if (vlan->clean)
724 vlan_dellink(vlan->ifname, hapd);
725 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
727 vlan = next;
732 int vlan_init(struct hostapd_data *hapd)
734 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
735 return -1;
737 #ifdef CONFIG_FULL_DYNAMIC_VLAN
738 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
739 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
741 return 0;
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))
760 return -1;
762 return 0;
766 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
767 struct hostapd_vlan *vlan,
768 int vlan_id)
770 struct hostapd_vlan *n;
771 char *ifname, *pos;
773 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
774 vlan->vlan_id != VLAN_ID_WILDCARD)
775 return NULL;
777 ifname = strdup(vlan->ifname);
778 if (ifname == NULL)
779 return NULL;
780 pos = strchr(ifname, '#');
781 if (pos == NULL) {
782 free(ifname);
783 return NULL;
785 *pos++ = '\0';
787 n = malloc(sizeof(*n));
788 if (n == NULL) {
789 free(ifname);
790 return NULL;
793 memset(n, 0, sizeof(*n));
794 n->vlan_id = vlan_id;
795 n->dynamic_vlan = 1;
797 snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, pos);
798 free(ifname);
800 if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
801 free(n);
802 return NULL;
805 n->next = hapd->conf->vlan;
806 hapd->conf->vlan = n;
808 return 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)
817 return 1;
819 vlan = hapd->conf->vlan;
820 while (vlan) {
821 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
822 vlan->dynamic_vlan--;
823 break;
825 vlan = vlan->next;
828 if (vlan == NULL)
829 return 1;
831 if (vlan->dynamic_vlan == 0)
832 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
834 return 0;