1d9d68e3af5cb4f077930498ce0bdeb35d64427a
[libeap.git] / src / ap / vlan_init.c
1 /*
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>
6  *
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.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See README and COPYING for more details.
15  */
16
17 #include "utils/includes.h"
18
19 #include "utils/common.h"
20 #include "hostapd.h"
21 #include "ap_config.h"
22 #include "vlan_init.h"
23
24
25 #ifdef CONFIG_FULL_DYNAMIC_VLAN
26
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29 #include <linux/sockios.h>
30 #include <linux/if_vlan.h>
31 #include <linux/if_bridge.h>
32
33 #include "drivers/priv_netlink.h"
34 #include "utils/eloop.h"
35
36
37 struct full_dynamic_vlan {
38         int s; /* socket on which to listen for new/removed interfaces. */
39 };
40
41
42 static int ifconfig_helper(const char *if_name, int up)
43 {
44         int fd;
45         struct ifreq ifr;
46
47         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
48                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
49                            "failed: %s", __func__, strerror(errno));
50                 return -1;
51         }
52
53         os_memset(&ifr, 0, sizeof(ifr));
54         os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
55
56         if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
57                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
58                            "for interface %s: %s",
59                            __func__, if_name, strerror(errno));
60                 close(fd);
61                 return -1;
62         }
63
64         if (up)
65                 ifr.ifr_flags |= IFF_UP;
66         else
67                 ifr.ifr_flags &= ~IFF_UP;
68
69         if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
70                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
71                            "for interface %s (up=%d): %s",
72                            __func__, if_name, up, strerror(errno));
73                 close(fd);
74                 return -1;
75         }
76
77         close(fd);
78         return 0;
79 }
80
81
82 static int ifconfig_up(const char *if_name)
83 {
84         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
85         return ifconfig_helper(if_name, 1);
86 }
87
88
89 static int ifconfig_down(const char *if_name)
90 {
91         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
92         return ifconfig_helper(if_name, 0);
93 }
94
95
96 /*
97  * These are only available in recent linux headers (without the leading
98  * underscore).
99  */
100 #define _GET_VLAN_REALDEV_NAME_CMD      8
101 #define _GET_VLAN_VID_CMD               9
102
103 /* This value should be 256 ONLY. If it is something else, then hostapd
104  * might crash!, as this value has been hard-coded in 2.4.x kernel
105  * bridging code.
106  */
107 #define MAX_BR_PORTS                    256
108
109 static int br_delif(const char *br_name, const char *if_name)
110 {
111         int fd;
112         struct ifreq ifr;
113         unsigned long args[2];
114         int if_index;
115
116         wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
117         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
118                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
119                            "failed: %s", __func__, strerror(errno));
120                 return -1;
121         }
122
123         if_index = if_nametoindex(if_name);
124
125         if (if_index == 0) {
126                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
127                            "interface index for '%s'",
128                            __func__, if_name);
129                 close(fd);
130                 return -1;
131         }
132
133         args[0] = BRCTL_DEL_IF;
134         args[1] = if_index;
135
136         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
137         ifr.ifr_data = (__caddr_t) args;
138
139         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
140                 /* No error if interface already removed. */
141                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
142                            "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
143                            "%s", __func__, br_name, if_name, strerror(errno));
144                 close(fd);
145                 return -1;
146         }
147
148         close(fd);
149         return 0;
150 }
151
152
153 /*
154         Add interface 'if_name' to the bridge 'br_name'
155
156         returns -1 on error
157         returns 1 if the interface is already part of the bridge
158         returns 0 otherwise
159 */
160 static int br_addif(const char *br_name, const char *if_name)
161 {
162         int fd;
163         struct ifreq ifr;
164         unsigned long args[2];
165         int if_index;
166
167         wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
168         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
169                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
170                            "failed: %s", __func__, strerror(errno));
171                 return -1;
172         }
173
174         if_index = if_nametoindex(if_name);
175
176         if (if_index == 0) {
177                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
178                            "interface index for '%s'",
179                            __func__, if_name);
180                 close(fd);
181                 return -1;
182         }
183
184         args[0] = BRCTL_ADD_IF;
185         args[1] = if_index;
186
187         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
188         ifr.ifr_data = (__caddr_t) args;
189
190         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
191                 if (errno == EBUSY) {
192                         /* The interface is already added. */
193                         close(fd);
194                         return 1;
195                 }
196
197                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
198                            "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
199                            "%s", __func__, br_name, if_name, strerror(errno));
200                 close(fd);
201                 return -1;
202         }
203
204         close(fd);
205         return 0;
206 }
207
208
209 static int br_delbr(const char *br_name)
210 {
211         int fd;
212         unsigned long arg[2];
213
214         wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
215         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
216                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
217                            "failed: %s", __func__, strerror(errno));
218                 return -1;
219         }
220
221         arg[0] = BRCTL_DEL_BRIDGE;
222         arg[1] = (unsigned long) br_name;
223
224         if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
225                 /* No error if bridge already removed. */
226                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
227                            "%s: %s", __func__, br_name, strerror(errno));
228                 close(fd);
229                 return -1;
230         }
231
232         close(fd);
233         return 0;
234 }
235
236
237 /*
238         Add a bridge with the name 'br_name'.
239
240         returns -1 on error
241         returns 1 if the bridge already exists
242         returns 0 otherwise
243 */
244 static int br_addbr(const char *br_name)
245 {
246         int fd;
247         unsigned long arg[2];
248
249         wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
250         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
251                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
252                            "failed: %s", __func__, strerror(errno));
253                 return -1;
254         }
255
256         arg[0] = BRCTL_ADD_BRIDGE;
257         arg[1] = (unsigned long) br_name;
258
259         if (ioctl(fd, SIOCGIFBR, arg) < 0) {
260                 if (errno == EEXIST) {
261                         /* The bridge is already added. */
262                         close(fd);
263                         return 1;
264                 } else {
265                         wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
266                                    "failed for %s: %s",
267                                    __func__, br_name, strerror(errno));
268                         close(fd);
269                         return -1;
270                 }
271         }
272
273         close(fd);
274         return 0;
275 }
276
277
278 static int br_getnumports(const char *br_name)
279 {
280         int fd;
281         int i;
282         int port_cnt = 0;
283         unsigned long arg[4];
284         int ifindices[MAX_BR_PORTS];
285         struct ifreq ifr;
286
287         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
288                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
289                            "failed: %s", __func__, strerror(errno));
290                 return -1;
291         }
292
293         arg[0] = BRCTL_GET_PORT_LIST;
294         arg[1] = (unsigned long) ifindices;
295         arg[2] = MAX_BR_PORTS;
296         arg[3] = 0;
297
298         os_memset(ifindices, 0, sizeof(ifindices));
299         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
300         ifr.ifr_data = (__caddr_t) arg;
301
302         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
303                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
304                            "failed for %s: %s",
305                            __func__, br_name, strerror(errno));
306                 close(fd);
307                 return -1;
308         }
309
310         for (i = 1; i < MAX_BR_PORTS; i++) {
311                 if (ifindices[i] > 0) {
312                         port_cnt++;
313                 }
314         }
315
316         close(fd);
317         return port_cnt;
318 }
319
320
321 static int vlan_rem(const char *if_name)
322 {
323         int fd;
324         struct vlan_ioctl_args if_request;
325
326         wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
327         if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
328                 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
329                            if_name);
330                 return -1;
331         }
332
333         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
334                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
335                            "failed: %s", __func__, strerror(errno));
336                 return -1;
337         }
338
339         os_memset(&if_request, 0, sizeof(if_request));
340
341         os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
342         if_request.cmd = DEL_VLAN_CMD;
343
344         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
345                 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
346                            "%s", __func__, if_name, strerror(errno));
347                 close(fd);
348                 return -1;
349         }
350
351         close(fd);
352         return 0;
353 }
354
355
356 /*
357         Add a vlan interface with VLAN ID 'vid' and tagged interface
358         'if_name'.
359
360         returns -1 on error
361         returns 1 if the interface already exists
362         returns 0 otherwise
363 */
364 static int vlan_add(const char *if_name, int vid)
365 {
366         int fd;
367         struct vlan_ioctl_args if_request;
368
369         wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
370                    if_name, vid);
371         ifconfig_up(if_name);
372
373         if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
374                 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
375                            if_name);
376                 return -1;
377         }
378
379         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
380                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
381                            "failed: %s", __func__, strerror(errno));
382                 return -1;
383         }
384
385         os_memset(&if_request, 0, sizeof(if_request));
386
387         /* Determine if a suitable vlan device already exists. */
388
389         os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
390                     vid);
391
392         if_request.cmd = _GET_VLAN_VID_CMD;
393
394         if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
395
396                 if (if_request.u.VID == vid) {
397                         if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
398
399                         if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
400                             os_strncmp(if_request.u.device2, if_name,
401                                        sizeof(if_request.u.device2)) == 0) {
402                                 close(fd);
403                                 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
404                                            "if_name %s exists already",
405                                            if_request.device1);
406                                 return 1;
407                         }
408                 }
409         }
410
411         /* A suitable vlan device does not already exist, add one. */
412
413         os_memset(&if_request, 0, sizeof(if_request));
414         os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
415         if_request.u.VID = vid;
416         if_request.cmd = ADD_VLAN_CMD;
417
418         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
419                 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
420                            "%s",
421                            __func__, if_request.device1, strerror(errno));
422                 close(fd);
423                 return -1;
424         }
425
426         close(fd);
427         return 0;
428 }
429
430
431 static int vlan_set_name_type(unsigned int name_type)
432 {
433         int fd;
434         struct vlan_ioctl_args if_request;
435
436         wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
437                    name_type);
438         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
439                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
440                            "failed: %s", __func__, strerror(errno));
441                 return -1;
442         }
443
444         os_memset(&if_request, 0, sizeof(if_request));
445
446         if_request.u.name_type = name_type;
447         if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
448         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
449                 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
450                            "name_type=%u failed: %s",
451                            __func__, name_type, strerror(errno));
452                 close(fd);
453                 return -1;
454         }
455
456         close(fd);
457         return 0;
458 }
459
460
461 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
462 {
463         char vlan_ifname[IFNAMSIZ];
464         char br_name[IFNAMSIZ];
465         struct hostapd_vlan *vlan = hapd->conf->vlan;
466         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
467
468         wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
469
470         while (vlan) {
471                 if (os_strcmp(ifname, vlan->ifname) == 0) {
472
473                         os_snprintf(br_name, sizeof(br_name), "brvlan%d",
474                                     vlan->vlan_id);
475
476                         if (!br_addbr(br_name))
477                                 vlan->clean |= DVLAN_CLEAN_BR;
478
479                         ifconfig_up(br_name);
480
481                         if (tagged_interface) {
482
483                                 if (!vlan_add(tagged_interface, vlan->vlan_id))
484                                         vlan->clean |= DVLAN_CLEAN_VLAN;
485
486                                 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
487                                             "vlan%d", vlan->vlan_id);
488
489                                 if (!br_addif(br_name, vlan_ifname))
490                                         vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
491
492                                 ifconfig_up(vlan_ifname);
493                         }
494
495                         if (!br_addif(br_name, ifname))
496                                 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
497
498                         ifconfig_up(ifname);
499
500                         break;
501                 }
502                 vlan = vlan->next;
503         }
504 }
505
506
507 static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
508 {
509         char vlan_ifname[IFNAMSIZ];
510         char br_name[IFNAMSIZ];
511         struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
512         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
513         int numports;
514
515         wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
516
517         first = prev = vlan;
518
519         while (vlan) {
520                 if (os_strcmp(ifname, vlan->ifname) == 0) {
521                         os_snprintf(br_name, sizeof(br_name), "brvlan%d",
522                                     vlan->vlan_id);
523
524                         if (tagged_interface) {
525                                 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
526                                             "vlan%d", vlan->vlan_id);
527
528                                 numports = br_getnumports(br_name);
529                                 if (numports == 1) {
530                                         br_delif(br_name, vlan_ifname);
531
532                                         vlan_rem(vlan_ifname);
533
534                                         ifconfig_down(br_name);
535                                         br_delbr(br_name);
536                                 }
537                         }
538
539                         if (vlan == first) {
540                                 hapd->conf->vlan = vlan->next;
541                         } else {
542                                 prev->next = vlan->next;
543                         }
544                         os_free(vlan);
545
546                         break;
547                 }
548                 prev = vlan;
549                 vlan = vlan->next;
550         }
551 }
552
553
554 static void
555 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
556                   struct hostapd_data *hapd)
557 {
558         struct ifinfomsg *ifi;
559         int attrlen, nlmsg_len, rta_len;
560         struct rtattr *attr;
561
562         if (len < sizeof(*ifi))
563                 return;
564
565         ifi = NLMSG_DATA(h);
566
567         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
568
569         attrlen = h->nlmsg_len - nlmsg_len;
570         if (attrlen < 0)
571                 return;
572
573         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
574
575         rta_len = RTA_ALIGN(sizeof(struct rtattr));
576         while (RTA_OK(attr, attrlen)) {
577                 char ifname[IFNAMSIZ + 1];
578
579                 if (attr->rta_type == IFLA_IFNAME) {
580                         int n = attr->rta_len - rta_len;
581                         if (n < 0)
582                                 break;
583
584                         os_memset(ifname, 0, sizeof(ifname));
585
586                         if ((size_t) n > sizeof(ifname))
587                                 n = sizeof(ifname);
588                         os_memcpy(ifname, ((char *) attr) + rta_len, n);
589
590                         if (del)
591                                 vlan_dellink(ifname, hapd);
592                         else
593                                 vlan_newlink(ifname, hapd);
594                 }
595
596                 attr = RTA_NEXT(attr, attrlen);
597         }
598 }
599
600
601 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
602 {
603         char buf[8192];
604         int left;
605         struct sockaddr_nl from;
606         socklen_t fromlen;
607         struct nlmsghdr *h;
608         struct hostapd_data *hapd = eloop_ctx;
609
610         fromlen = sizeof(from);
611         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
612                         (struct sockaddr *) &from, &fromlen);
613         if (left < 0) {
614                 if (errno != EINTR && errno != EAGAIN)
615                         wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
616                                    __func__, strerror(errno));
617                 return;
618         }
619
620         h = (struct nlmsghdr *) buf;
621         while (left >= (int) sizeof(*h)) {
622                 int len, plen;
623
624                 len = h->nlmsg_len;
625                 plen = len - sizeof(*h);
626                 if (len > left || plen < 0) {
627                         wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
628                                    "message: len=%d left=%d plen=%d",
629                                    len, left, plen);
630                         break;
631                 }
632
633                 switch (h->nlmsg_type) {
634                 case RTM_NEWLINK:
635                         vlan_read_ifnames(h, plen, 0, hapd);
636                         break;
637                 case RTM_DELLINK:
638                         vlan_read_ifnames(h, plen, 1, hapd);
639                         break;
640                 }
641
642                 len = NLMSG_ALIGN(len);
643                 left -= len;
644                 h = (struct nlmsghdr *) ((char *) h + len);
645         }
646
647         if (left > 0) {
648                 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
649                            "netlink message", __func__, left);
650         }
651 }
652
653
654 static struct full_dynamic_vlan *
655 full_dynamic_vlan_init(struct hostapd_data *hapd)
656 {
657         struct sockaddr_nl local;
658         struct full_dynamic_vlan *priv;
659
660         priv = os_zalloc(sizeof(*priv));
661         if (priv == NULL)
662                 return NULL;
663
664         vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
665
666         priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
667         if (priv->s < 0) {
668                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
669                            "NETLINK_ROUTE) failed: %s",
670                            __func__, strerror(errno));
671                 os_free(priv);
672                 return NULL;
673         }
674
675         os_memset(&local, 0, sizeof(local));
676         local.nl_family = AF_NETLINK;
677         local.nl_groups = RTMGRP_LINK;
678         if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
679                 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
680                            __func__, strerror(errno));
681                 close(priv->s);
682                 os_free(priv);
683                 return NULL;
684         }
685
686         if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
687         {
688                 close(priv->s);
689                 os_free(priv);
690                 return NULL;
691         }
692
693         return priv;
694 }
695
696
697 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
698 {
699         if (priv == NULL)
700                 return;
701         eloop_unregister_read_sock(priv->s);
702         close(priv->s);
703         os_free(priv);
704 }
705 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
706
707
708 int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
709                               struct hostapd_ssid *mssid, const char *dyn_vlan)
710 {
711         int i;
712
713         if (dyn_vlan == NULL)
714                 return 0;
715
716         /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
717          * functions for setting up dynamic broadcast keys. */
718         for (i = 0; i < 4; i++) {
719                 if (mssid->wep.key[i] &&
720                     hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
721                                       i == mssid->wep.idx, NULL, 0,
722                                       mssid->wep.key[i], mssid->wep.len[i])) {
723                         wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
724                                    "encryption for dynamic VLAN");
725                         return -1;
726                 }
727         }
728
729         return 0;
730 }
731
732
733 static int vlan_dynamic_add(struct hostapd_data *hapd,
734                             struct hostapd_vlan *vlan)
735 {
736         while (vlan) {
737                 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
738                     hapd->drv.vlan_if_add(hapd, vlan->ifname)) {
739                         if (errno != EEXIST) {
740                                 wpa_printf(MSG_ERROR, "VLAN: Could not add "
741                                            "VLAN iface: %s: %s",
742                                            vlan->ifname, strerror(errno));
743                                 return -1;
744                         }
745                 }
746
747                 vlan = vlan->next;
748         }
749
750         return 0;
751 }
752
753
754 static void vlan_dynamic_remove(struct hostapd_data *hapd,
755                                 struct hostapd_vlan *vlan)
756 {
757         struct hostapd_vlan *next;
758
759         while (vlan) {
760                 next = vlan->next;
761
762                 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
763                     hapd->drv.vlan_if_remove(hapd, vlan->ifname)) {
764                         wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
765                                    "iface: %s: %s",
766                                    vlan->ifname, strerror(errno));
767                 }
768 #ifdef CONFIG_FULL_DYNAMIC_VLAN
769                 if (vlan->clean)
770                         vlan_dellink(vlan->ifname, hapd);
771 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
772
773                 vlan = next;
774         }
775 }
776
777
778 int vlan_init(struct hostapd_data *hapd)
779 {
780         if (vlan_dynamic_add(hapd, hapd->conf->vlan))
781                 return -1;
782
783 #ifdef CONFIG_FULL_DYNAMIC_VLAN
784         hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
785 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
786
787         return 0;
788 }
789
790
791 void vlan_deinit(struct hostapd_data *hapd)
792 {
793         vlan_dynamic_remove(hapd, hapd->conf->vlan);
794
795 #ifdef CONFIG_FULL_DYNAMIC_VLAN
796         full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
797 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
798 }
799
800
801 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
802                                        struct hostapd_vlan *vlan,
803                                        int vlan_id)
804 {
805         struct hostapd_vlan *n;
806         char *ifname, *pos;
807
808         if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
809             vlan->vlan_id != VLAN_ID_WILDCARD)
810                 return NULL;
811
812         wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
813                    __func__, vlan_id, vlan->ifname);
814         ifname = os_strdup(vlan->ifname);
815         if (ifname == NULL)
816                 return NULL;
817         pos = os_strchr(ifname, '#');
818         if (pos == NULL) {
819                 os_free(ifname);
820                 return NULL;
821         }
822         *pos++ = '\0';
823
824         n = os_zalloc(sizeof(*n));
825         if (n == NULL) {
826                 os_free(ifname);
827                 return NULL;
828         }
829
830         n->vlan_id = vlan_id;
831         n->dynamic_vlan = 1;
832
833         os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
834                     pos);
835         os_free(ifname);
836
837         if (hapd->drv.vlan_if_add(hapd, n->ifname)) {
838                 os_free(n);
839                 return NULL;
840         }
841
842         n->next = hapd->conf->vlan;
843         hapd->conf->vlan = n;
844
845         return n;
846 }
847
848
849 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
850 {
851         struct hostapd_vlan *vlan;
852
853         if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
854                 return 1;
855
856         wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
857
858         vlan = hapd->conf->vlan;
859         while (vlan) {
860                 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
861                         vlan->dynamic_vlan--;
862                         break;
863                 }
864                 vlan = vlan->next;
865         }
866
867         if (vlan == NULL)
868                 return 1;
869
870         if (vlan->dynamic_vlan == 0)
871                 hapd->drv.vlan_if_remove(hapd, vlan->ifname);
872
873         return 0;
874 }