Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / 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 software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10
11 #include "utils/includes.h"
12 #ifdef CONFIG_FULL_DYNAMIC_VLAN
13 #include <net/if.h>
14 #include <sys/ioctl.h>
15 #include <linux/sockios.h>
16 #include <linux/if_vlan.h>
17 #include <linux/if_bridge.h>
18 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
19
20 #include "utils/common.h"
21 #include "hostapd.h"
22 #include "ap_config.h"
23 #include "ap_drv_ops.h"
24 #include "vlan_init.h"
25 #include "vlan_util.h"
26
27
28 #ifdef CONFIG_FULL_DYNAMIC_VLAN
29
30 #include "drivers/priv_netlink.h"
31 #include "utils/eloop.h"
32
33
34 struct full_dynamic_vlan {
35         int s; /* socket on which to listen for new/removed interfaces. */
36 };
37
38 #define DVLAN_CLEAN_BR         0x1
39 #define DVLAN_CLEAN_VLAN       0x2
40 #define DVLAN_CLEAN_VLAN_PORT  0x4
41
42 struct dynamic_iface {
43         char ifname[IFNAMSIZ + 1];
44         int usage;
45         int clean;
46         struct dynamic_iface *next;
47 };
48
49
50 /* Increment ref counter for ifname and add clean flag.
51  * If not in list, add it only if some flags are given.
52  */
53 static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
54                           int clean)
55 {
56         struct dynamic_iface *next, **dynamic_ifaces;
57         struct hapd_interfaces *interfaces;
58
59         interfaces = hapd->iface->interfaces;
60         dynamic_ifaces = &interfaces->vlan_priv;
61
62         for (next = *dynamic_ifaces; next; next = next->next) {
63                 if (os_strcmp(ifname, next->ifname) == 0)
64                         break;
65         }
66
67         if (next) {
68                 next->usage++;
69                 next->clean |= clean;
70                 return;
71         }
72
73         if (!clean)
74                 return;
75
76         next = os_zalloc(sizeof(*next));
77         if (!next)
78                 return;
79         os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
80         next->usage = 1;
81         next->clean = clean;
82         next->next = *dynamic_ifaces;
83         *dynamic_ifaces = next;
84 }
85
86
87 /* Decrement reference counter for given ifname.
88  * Return clean flag iff reference counter was decreased to zero, else zero
89  */
90 static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
91 {
92         struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
93         struct hapd_interfaces *interfaces;
94         int clean;
95
96         interfaces = hapd->iface->interfaces;
97         dynamic_ifaces = &interfaces->vlan_priv;
98
99         for (next = *dynamic_ifaces; next; next = next->next) {
100                 if (os_strcmp(ifname, next->ifname) == 0)
101                         break;
102                 prev = next;
103         }
104
105         if (!next)
106                 return 0;
107
108         next->usage--;
109         if (next->usage)
110                 return 0;
111
112         if (prev)
113                 prev->next = next->next;
114         else
115                 *dynamic_ifaces = next->next;
116         clean = next->clean;
117         os_free(next);
118
119         return clean;
120 }
121
122
123 static int ifconfig_helper(const char *if_name, int up)
124 {
125         int fd;
126         struct ifreq ifr;
127
128         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
129                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
130                            "failed: %s", __func__, strerror(errno));
131                 return -1;
132         }
133
134         os_memset(&ifr, 0, sizeof(ifr));
135         os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
136
137         if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
138                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
139                            "for interface %s: %s",
140                            __func__, if_name, strerror(errno));
141                 close(fd);
142                 return -1;
143         }
144
145         if (up)
146                 ifr.ifr_flags |= IFF_UP;
147         else
148                 ifr.ifr_flags &= ~IFF_UP;
149
150         if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
151                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
152                            "for interface %s (up=%d): %s",
153                            __func__, if_name, up, strerror(errno));
154                 close(fd);
155                 return -1;
156         }
157
158         close(fd);
159         return 0;
160 }
161
162
163 static int ifconfig_up(const char *if_name)
164 {
165         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
166         return ifconfig_helper(if_name, 1);
167 }
168
169
170 static int ifconfig_down(const char *if_name)
171 {
172         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
173         return ifconfig_helper(if_name, 0);
174 }
175
176
177 /*
178  * These are only available in recent linux headers (without the leading
179  * underscore).
180  */
181 #define _GET_VLAN_REALDEV_NAME_CMD      8
182 #define _GET_VLAN_VID_CMD               9
183
184 /* This value should be 256 ONLY. If it is something else, then hostapd
185  * might crash!, as this value has been hard-coded in 2.4.x kernel
186  * bridging code.
187  */
188 #define MAX_BR_PORTS                    256
189
190 static int br_delif(const char *br_name, const char *if_name)
191 {
192         int fd;
193         struct ifreq ifr;
194         unsigned long args[2];
195         int if_index;
196
197         wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
198         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
199                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
200                            "failed: %s", __func__, strerror(errno));
201                 return -1;
202         }
203
204         if_index = if_nametoindex(if_name);
205
206         if (if_index == 0) {
207                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
208                            "interface index for '%s'",
209                            __func__, if_name);
210                 close(fd);
211                 return -1;
212         }
213
214         args[0] = BRCTL_DEL_IF;
215         args[1] = if_index;
216
217         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
218         ifr.ifr_data = (__caddr_t) args;
219
220         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
221                 /* No error if interface already removed. */
222                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
223                            "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
224                            "%s", __func__, br_name, if_name, strerror(errno));
225                 close(fd);
226                 return -1;
227         }
228
229         close(fd);
230         return 0;
231 }
232
233
234 /*
235         Add interface 'if_name' to the bridge 'br_name'
236
237         returns -1 on error
238         returns 1 if the interface is already part of the bridge
239         returns 0 otherwise
240 */
241 static int br_addif(const char *br_name, const char *if_name)
242 {
243         int fd;
244         struct ifreq ifr;
245         unsigned long args[2];
246         int if_index;
247
248         wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
249         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
250                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
251                            "failed: %s", __func__, strerror(errno));
252                 return -1;
253         }
254
255         if_index = if_nametoindex(if_name);
256
257         if (if_index == 0) {
258                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
259                            "interface index for '%s'",
260                            __func__, if_name);
261                 close(fd);
262                 return -1;
263         }
264
265         args[0] = BRCTL_ADD_IF;
266         args[1] = if_index;
267
268         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
269         ifr.ifr_data = (__caddr_t) args;
270
271         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
272                 if (errno == EBUSY) {
273                         /* The interface is already added. */
274                         close(fd);
275                         return 1;
276                 }
277
278                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
279                            "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
280                            "%s", __func__, br_name, if_name, strerror(errno));
281                 close(fd);
282                 return -1;
283         }
284
285         close(fd);
286         return 0;
287 }
288
289
290 static int br_delbr(const char *br_name)
291 {
292         int fd;
293         unsigned long arg[2];
294
295         wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
296         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
297                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
298                            "failed: %s", __func__, strerror(errno));
299                 return -1;
300         }
301
302         arg[0] = BRCTL_DEL_BRIDGE;
303         arg[1] = (unsigned long) br_name;
304
305         if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
306                 /* No error if bridge already removed. */
307                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
308                            "%s: %s", __func__, br_name, strerror(errno));
309                 close(fd);
310                 return -1;
311         }
312
313         close(fd);
314         return 0;
315 }
316
317
318 /*
319         Add a bridge with the name 'br_name'.
320
321         returns -1 on error
322         returns 1 if the bridge already exists
323         returns 0 otherwise
324 */
325 static int br_addbr(const char *br_name)
326 {
327         int fd;
328         unsigned long arg[4];
329         struct ifreq ifr;
330
331         wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
332         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
333                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
334                            "failed: %s", __func__, strerror(errno));
335                 return -1;
336         }
337
338         arg[0] = BRCTL_ADD_BRIDGE;
339         arg[1] = (unsigned long) br_name;
340
341         if (ioctl(fd, SIOCGIFBR, arg) < 0) {
342                 if (errno == EEXIST) {
343                         /* The bridge is already added. */
344                         close(fd);
345                         return 1;
346                 } else {
347                         wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
348                                    "failed for %s: %s",
349                                    __func__, br_name, strerror(errno));
350                         close(fd);
351                         return -1;
352                 }
353         }
354
355         /* Decrease forwarding delay to avoid EAPOL timeouts. */
356         os_memset(&ifr, 0, sizeof(ifr));
357         os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
358         arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
359         arg[1] = 1;
360         arg[2] = 0;
361         arg[3] = 0;
362         ifr.ifr_data = (char *) &arg;
363         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
364                 wpa_printf(MSG_ERROR, "VLAN: %s: "
365                            "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
366                            "%s: %s", __func__, br_name, strerror(errno));
367                 /* Continue anyway */
368         }
369
370         close(fd);
371         return 0;
372 }
373
374
375 static int br_getnumports(const char *br_name)
376 {
377         int fd;
378         int i;
379         int port_cnt = 0;
380         unsigned long arg[4];
381         int ifindices[MAX_BR_PORTS];
382         struct ifreq ifr;
383
384         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
385                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
386                            "failed: %s", __func__, strerror(errno));
387                 return -1;
388         }
389
390         arg[0] = BRCTL_GET_PORT_LIST;
391         arg[1] = (unsigned long) ifindices;
392         arg[2] = MAX_BR_PORTS;
393         arg[3] = 0;
394
395         os_memset(ifindices, 0, sizeof(ifindices));
396         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
397         ifr.ifr_data = (__caddr_t) arg;
398
399         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
400                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
401                            "failed for %s: %s",
402                            __func__, br_name, strerror(errno));
403                 close(fd);
404                 return -1;
405         }
406
407         for (i = 1; i < MAX_BR_PORTS; i++) {
408                 if (ifindices[i] > 0) {
409                         port_cnt++;
410                 }
411         }
412
413         close(fd);
414         return port_cnt;
415 }
416
417
418 #ifndef CONFIG_VLAN_NETLINK
419
420 int vlan_rem(const char *if_name)
421 {
422         int fd;
423         struct vlan_ioctl_args if_request;
424
425         wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
426         if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
427                 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
428                            if_name);
429                 return -1;
430         }
431
432         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
433                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
434                            "failed: %s", __func__, strerror(errno));
435                 return -1;
436         }
437
438         os_memset(&if_request, 0, sizeof(if_request));
439
440         os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
441         if_request.cmd = DEL_VLAN_CMD;
442
443         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
444                 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
445                            "%s", __func__, if_name, strerror(errno));
446                 close(fd);
447                 return -1;
448         }
449
450         close(fd);
451         return 0;
452 }
453
454
455 /*
456         Add a vlan interface with VLAN ID 'vid' and tagged interface
457         'if_name'.
458
459         returns -1 on error
460         returns 1 if the interface already exists
461         returns 0 otherwise
462 */
463 int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
464 {
465         int fd;
466         struct vlan_ioctl_args if_request;
467
468         wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
469                    if_name, vid);
470         ifconfig_up(if_name);
471
472         if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
473                 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
474                            if_name);
475                 return -1;
476         }
477
478         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
479                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
480                            "failed: %s", __func__, strerror(errno));
481                 return -1;
482         }
483
484         os_memset(&if_request, 0, sizeof(if_request));
485
486         /* Determine if a suitable vlan device already exists. */
487
488         os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
489                     vid);
490
491         if_request.cmd = _GET_VLAN_VID_CMD;
492
493         if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
494
495                 if (if_request.u.VID == vid) {
496                         if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
497
498                         if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
499                             os_strncmp(if_request.u.device2, if_name,
500                                        sizeof(if_request.u.device2)) == 0) {
501                                 close(fd);
502                                 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
503                                            "if_name %s exists already",
504                                            if_request.device1);
505                                 return 1;
506                         }
507                 }
508         }
509
510         /* A suitable vlan device does not already exist, add one. */
511
512         os_memset(&if_request, 0, sizeof(if_request));
513         os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
514         if_request.u.VID = vid;
515         if_request.cmd = ADD_VLAN_CMD;
516
517         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
518                 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
519                            "%s",
520                            __func__, if_request.device1, strerror(errno));
521                 close(fd);
522                 return -1;
523         }
524
525         close(fd);
526         return 0;
527 }
528
529
530 static int vlan_set_name_type(unsigned int name_type)
531 {
532         int fd;
533         struct vlan_ioctl_args if_request;
534
535         wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
536                    name_type);
537         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
538                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
539                            "failed: %s", __func__, strerror(errno));
540                 return -1;
541         }
542
543         os_memset(&if_request, 0, sizeof(if_request));
544
545         if_request.u.name_type = name_type;
546         if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
547         if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
548                 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
549                            "name_type=%u failed: %s",
550                            __func__, name_type, strerror(errno));
551                 close(fd);
552                 return -1;
553         }
554
555         close(fd);
556         return 0;
557 }
558
559 #endif /* CONFIG_VLAN_NETLINK */
560
561
562 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
563 {
564         char vlan_ifname[IFNAMSIZ];
565         char br_name[IFNAMSIZ];
566         struct hostapd_vlan *vlan = hapd->conf->vlan;
567         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
568         int vlan_naming = hapd->conf->ssid.vlan_naming;
569         int clean;
570
571         wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
572
573         while (vlan) {
574                 if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
575                         vlan->configured = 1;
576
577                         if (hapd->conf->vlan_bridge[0]) {
578                                 os_snprintf(br_name, sizeof(br_name), "%s%d",
579                                             hapd->conf->vlan_bridge,
580                                             vlan->vlan_id);
581                         } else if (tagged_interface) {
582                                 os_snprintf(br_name, sizeof(br_name),
583                                             "br%s.%d", tagged_interface,
584                                             vlan->vlan_id);
585                         } else {
586                                 os_snprintf(br_name, sizeof(br_name),
587                                             "brvlan%d", vlan->vlan_id);
588                         }
589
590                         dyn_iface_get(hapd, br_name,
591                                       br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
592
593                         ifconfig_up(br_name);
594
595                         if (tagged_interface) {
596                                 if (vlan_naming ==
597                                     DYNAMIC_VLAN_NAMING_WITH_DEVICE)
598                                         os_snprintf(vlan_ifname,
599                                                     sizeof(vlan_ifname),
600                                                     "%s.%d", tagged_interface,
601                                                     vlan->vlan_id);
602                                 else
603                                         os_snprintf(vlan_ifname,
604                                                     sizeof(vlan_ifname),
605                                                     "vlan%d", vlan->vlan_id);
606
607                                 clean = 0;
608                                 ifconfig_up(tagged_interface);
609                                 if (!vlan_add(tagged_interface, vlan->vlan_id,
610                                               vlan_ifname))
611                                         clean |= DVLAN_CLEAN_VLAN;
612
613                                 if (!br_addif(br_name, vlan_ifname))
614                                         clean |= DVLAN_CLEAN_VLAN_PORT;
615
616                                 dyn_iface_get(hapd, vlan_ifname, clean);
617
618                                 ifconfig_up(vlan_ifname);
619                         }
620
621                         if (!br_addif(br_name, ifname))
622                                 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
623
624                         ifconfig_up(ifname);
625
626                         break;
627                 }
628                 vlan = vlan->next;
629         }
630 }
631
632
633 static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
634 {
635         char vlan_ifname[IFNAMSIZ];
636         char br_name[IFNAMSIZ];
637         struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
638         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
639         int vlan_naming = hapd->conf->ssid.vlan_naming;
640         int clean;
641
642         wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
643
644         first = prev = vlan;
645
646         while (vlan) {
647                 if (os_strcmp(ifname, vlan->ifname) == 0 &&
648                     vlan->configured) {
649                         if (hapd->conf->vlan_bridge[0]) {
650                                 os_snprintf(br_name, sizeof(br_name), "%s%d",
651                                             hapd->conf->vlan_bridge,
652                                             vlan->vlan_id);
653                         } else if (tagged_interface) {
654                                 os_snprintf(br_name, sizeof(br_name),
655                                             "br%s.%d", tagged_interface,
656                                             vlan->vlan_id);
657                         } else {
658                                 os_snprintf(br_name, sizeof(br_name),
659                                             "brvlan%d", vlan->vlan_id);
660                         }
661
662                         if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
663                                 br_delif(br_name, vlan->ifname);
664
665                         if (tagged_interface) {
666                                 if (vlan_naming ==
667                                     DYNAMIC_VLAN_NAMING_WITH_DEVICE)
668                                         os_snprintf(vlan_ifname,
669                                                     sizeof(vlan_ifname),
670                                                     "%s.%d", tagged_interface,
671                                                     vlan->vlan_id);
672                                 else
673                                         os_snprintf(vlan_ifname,
674                                                     sizeof(vlan_ifname),
675                                                     "vlan%d", vlan->vlan_id);
676
677                                 clean = dyn_iface_put(hapd, vlan_ifname);
678
679                                 if (clean & DVLAN_CLEAN_VLAN_PORT)
680                                         br_delif(br_name, vlan_ifname);
681
682                                 if (clean & DVLAN_CLEAN_VLAN) {
683                                         ifconfig_down(vlan_ifname);
684                                         vlan_rem(vlan_ifname);
685                                 }
686                         }
687
688                         clean = dyn_iface_put(hapd, br_name);
689                         if ((clean & DVLAN_CLEAN_BR) &&
690                             br_getnumports(br_name) == 0) {
691                                 ifconfig_down(br_name);
692                                 br_delbr(br_name);
693                         }
694                 }
695
696                 if (os_strcmp(ifname, vlan->ifname) == 0) {
697                         if (vlan == first) {
698                                 hapd->conf->vlan = vlan->next;
699                         } else {
700                                 prev->next = vlan->next;
701                         }
702                         os_free(vlan);
703
704                         break;
705                 }
706                 prev = vlan;
707                 vlan = vlan->next;
708         }
709 }
710
711
712 static void
713 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
714                   struct hostapd_data *hapd)
715 {
716         struct ifinfomsg *ifi;
717         int attrlen, nlmsg_len, rta_len;
718         struct rtattr *attr;
719         char ifname[IFNAMSIZ + 1];
720
721         if (len < sizeof(*ifi))
722                 return;
723
724         ifi = NLMSG_DATA(h);
725
726         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
727
728         attrlen = h->nlmsg_len - nlmsg_len;
729         if (attrlen < 0)
730                 return;
731
732         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
733
734         os_memset(ifname, 0, sizeof(ifname));
735         rta_len = RTA_ALIGN(sizeof(struct rtattr));
736         while (RTA_OK(attr, attrlen)) {
737                 if (attr->rta_type == IFLA_IFNAME) {
738                         int n = attr->rta_len - rta_len;
739                         if (n < 0)
740                                 break;
741
742                         if ((size_t) n >= sizeof(ifname))
743                                 n = sizeof(ifname) - 1;
744                         os_memcpy(ifname, ((char *) attr) + rta_len, n);
745
746                 }
747
748                 attr = RTA_NEXT(attr, attrlen);
749         }
750
751         if (!ifname[0])
752                 return;
753         if (del && if_nametoindex(ifname)) {
754                  /* interface still exists, race condition ->
755                   * iface has just been recreated */
756                 return;
757         }
758
759         wpa_printf(MSG_DEBUG,
760                    "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
761                    del ? "DEL" : "NEW",
762                    ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
763                    (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
764                    (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
765                    (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
766                    (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
767
768         if (del)
769                 vlan_dellink(ifname, hapd);
770         else
771                 vlan_newlink(ifname, hapd);
772 }
773
774
775 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
776 {
777         char buf[8192];
778         int left;
779         struct sockaddr_nl from;
780         socklen_t fromlen;
781         struct nlmsghdr *h;
782         struct hostapd_data *hapd = eloop_ctx;
783
784         fromlen = sizeof(from);
785         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
786                         (struct sockaddr *) &from, &fromlen);
787         if (left < 0) {
788                 if (errno != EINTR && errno != EAGAIN)
789                         wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
790                                    __func__, strerror(errno));
791                 return;
792         }
793
794         h = (struct nlmsghdr *) buf;
795         while (NLMSG_OK(h, left)) {
796                 int len, plen;
797
798                 len = h->nlmsg_len;
799                 plen = len - sizeof(*h);
800                 if (len > left || plen < 0) {
801                         wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
802                                    "message: len=%d left=%d plen=%d",
803                                    len, left, plen);
804                         break;
805                 }
806
807                 switch (h->nlmsg_type) {
808                 case RTM_NEWLINK:
809                         vlan_read_ifnames(h, plen, 0, hapd);
810                         break;
811                 case RTM_DELLINK:
812                         vlan_read_ifnames(h, plen, 1, hapd);
813                         break;
814                 }
815
816                 h = NLMSG_NEXT(h, left);
817         }
818
819         if (left > 0) {
820                 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
821                            "netlink message", __func__, left);
822         }
823 }
824
825
826 static struct full_dynamic_vlan *
827 full_dynamic_vlan_init(struct hostapd_data *hapd)
828 {
829         struct sockaddr_nl local;
830         struct full_dynamic_vlan *priv;
831
832         priv = os_zalloc(sizeof(*priv));
833         if (priv == NULL)
834                 return NULL;
835
836 #ifndef CONFIG_VLAN_NETLINK
837         vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
838                            DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
839                            VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
840                            VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
841 #endif /* CONFIG_VLAN_NETLINK */
842
843         priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
844         if (priv->s < 0) {
845                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
846                            "NETLINK_ROUTE) failed: %s",
847                            __func__, strerror(errno));
848                 os_free(priv);
849                 return NULL;
850         }
851
852         os_memset(&local, 0, sizeof(local));
853         local.nl_family = AF_NETLINK;
854         local.nl_groups = RTMGRP_LINK;
855         if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
856                 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
857                            __func__, strerror(errno));
858                 close(priv->s);
859                 os_free(priv);
860                 return NULL;
861         }
862
863         if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
864         {
865                 close(priv->s);
866                 os_free(priv);
867                 return NULL;
868         }
869
870         return priv;
871 }
872
873
874 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
875 {
876         if (priv == NULL)
877                 return;
878         eloop_unregister_read_sock(priv->s);
879         close(priv->s);
880         os_free(priv);
881 }
882 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
883
884
885 int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
886 {
887         int i;
888
889         if (dyn_vlan == NULL)
890                 return 0;
891
892         /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
893          * functions for setting up dynamic broadcast keys. */
894         for (i = 0; i < 4; i++) {
895                 if (hapd->conf->ssid.wep.key[i] &&
896                     hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
897                                         i == hapd->conf->ssid.wep.idx, NULL, 0,
898                                         hapd->conf->ssid.wep.key[i],
899                                         hapd->conf->ssid.wep.len[i]))
900                 {
901                         wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
902                                    "encryption for dynamic VLAN");
903                         return -1;
904                 }
905         }
906
907         return 0;
908 }
909
910
911 static int vlan_dynamic_add(struct hostapd_data *hapd,
912                             struct hostapd_vlan *vlan)
913 {
914         while (vlan) {
915                 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
916                         if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
917                                 if (errno != EEXIST) {
918                                         wpa_printf(MSG_ERROR, "VLAN: Could "
919                                                    "not add VLAN %s: %s",
920                                                    vlan->ifname,
921                                                    strerror(errno));
922                                         return -1;
923                                 }
924                         }
925 #ifdef CONFIG_FULL_DYNAMIC_VLAN
926                         ifconfig_up(vlan->ifname);
927 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
928                 }
929
930                 vlan = vlan->next;
931         }
932
933         return 0;
934 }
935
936
937 static void vlan_dynamic_remove(struct hostapd_data *hapd,
938                                 struct hostapd_vlan *vlan)
939 {
940         struct hostapd_vlan *next;
941
942         while (vlan) {
943                 next = vlan->next;
944
945                 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
946                     hostapd_vlan_if_remove(hapd, vlan->ifname)) {
947                         wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
948                                    "iface: %s: %s",
949                                    vlan->ifname, strerror(errno));
950                 }
951 #ifdef CONFIG_FULL_DYNAMIC_VLAN
952                 if (vlan->clean)
953                         vlan_dellink(vlan->ifname, hapd);
954 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
955
956                 vlan = next;
957         }
958 }
959
960
961 int vlan_init(struct hostapd_data *hapd)
962 {
963 #ifdef CONFIG_FULL_DYNAMIC_VLAN
964         hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
965 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
966
967         if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
968             !hapd->conf->vlan) {
969                 /* dynamic vlans enabled but no (or empty) vlan_file given */
970                 struct hostapd_vlan *vlan;
971                 vlan = os_zalloc(sizeof(*vlan));
972                 if (vlan == NULL) {
973                         wpa_printf(MSG_ERROR, "Out of memory while assigning "
974                                    "VLAN interfaces");
975                         return -1;
976                 }
977
978                 vlan->vlan_id = VLAN_ID_WILDCARD;
979                 os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
980                             hapd->conf->iface);
981                 vlan->next = hapd->conf->vlan;
982                 hapd->conf->vlan = vlan;
983         }
984
985         if (vlan_dynamic_add(hapd, hapd->conf->vlan))
986                 return -1;
987
988         return 0;
989 }
990
991
992 void vlan_deinit(struct hostapd_data *hapd)
993 {
994         vlan_dynamic_remove(hapd, hapd->conf->vlan);
995
996 #ifdef CONFIG_FULL_DYNAMIC_VLAN
997         full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
998         hapd->full_dynamic_vlan = NULL;
999 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1000 }
1001
1002
1003 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
1004                                        struct hostapd_vlan *vlan,
1005                                        int vlan_id)
1006 {
1007         struct hostapd_vlan *n = NULL;
1008         char *ifname, *pos;
1009
1010         if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
1011             vlan->vlan_id != VLAN_ID_WILDCARD)
1012                 return NULL;
1013
1014         wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
1015                    __func__, vlan_id, vlan->ifname);
1016         ifname = os_strdup(vlan->ifname);
1017         if (ifname == NULL)
1018                 return NULL;
1019         pos = os_strchr(ifname, '#');
1020         if (pos == NULL)
1021                 goto free_ifname;
1022         *pos++ = '\0';
1023
1024         n = os_zalloc(sizeof(*n));
1025         if (n == NULL)
1026                 goto free_ifname;
1027
1028         n->vlan_id = vlan_id;
1029         n->dynamic_vlan = 1;
1030
1031         os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
1032                     pos);
1033
1034         if (hostapd_vlan_if_add(hapd, n->ifname)) {
1035                 os_free(n);
1036                 n = NULL;
1037                 goto free_ifname;
1038         }
1039
1040         n->next = hapd->conf->vlan;
1041         hapd->conf->vlan = n;
1042
1043 #ifdef CONFIG_FULL_DYNAMIC_VLAN
1044         ifconfig_up(n->ifname);
1045 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1046
1047 free_ifname:
1048         os_free(ifname);
1049         return n;
1050 }
1051
1052
1053 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
1054 {
1055         struct hostapd_vlan *vlan;
1056
1057         if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
1058                 return 1;
1059
1060         wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
1061                    __func__, hapd->conf->iface, vlan_id);
1062
1063         vlan = hapd->conf->vlan;
1064         while (vlan) {
1065                 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
1066                         vlan->dynamic_vlan--;
1067                         break;
1068                 }
1069                 vlan = vlan->next;
1070         }
1071
1072         if (vlan == NULL)
1073                 return 1;
1074
1075         if (vlan->dynamic_vlan == 0) {
1076                 hostapd_vlan_if_remove(hapd, vlan->ifname);
1077 #ifdef CONFIG_FULL_DYNAMIC_VLAN
1078                 vlan_dellink(vlan->ifname, hapd);
1079 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1080         }
1081
1082         return 0;
1083 }