]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/ap/vlan_full.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / ap / vlan_full.c
1 /*
2  * hostapd / VLAN initialization - full dynamic VLAN
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 #include <net/if.h>
13 /* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
14 #undef if_type
15 #include <sys/ioctl.h>
16
17 #include "utils/common.h"
18 #include "drivers/priv_netlink.h"
19 #include "drivers/linux_ioctl.h"
20 #include "common/linux_bridge.h"
21 #include "common/linux_vlan.h"
22 #include "utils/eloop.h"
23 #include "hostapd.h"
24 #include "ap_config.h"
25 #include "ap_drv_ops.h"
26 #include "wpa_auth.h"
27 #include "vlan_init.h"
28 #include "vlan_util.h"
29
30
31 struct full_dynamic_vlan {
32         int s; /* socket on which to listen for new/removed interfaces. */
33 };
34
35 #define DVLAN_CLEAN_BR         0x1
36 #define DVLAN_CLEAN_VLAN       0x2
37 #define DVLAN_CLEAN_VLAN_PORT  0x4
38
39 struct dynamic_iface {
40         char ifname[IFNAMSIZ + 1];
41         int usage;
42         int clean;
43         struct dynamic_iface *next;
44 };
45
46
47 /* Increment ref counter for ifname and add clean flag.
48  * If not in list, add it only if some flags are given.
49  */
50 static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
51                           int clean)
52 {
53         struct dynamic_iface *next, **dynamic_ifaces;
54         struct hapd_interfaces *interfaces;
55
56         interfaces = hapd->iface->interfaces;
57         dynamic_ifaces = &interfaces->vlan_priv;
58
59         for (next = *dynamic_ifaces; next; next = next->next) {
60                 if (os_strcmp(ifname, next->ifname) == 0)
61                         break;
62         }
63
64         if (next) {
65                 next->usage++;
66                 next->clean |= clean;
67                 return;
68         }
69
70         if (!clean)
71                 return;
72
73         next = os_zalloc(sizeof(*next));
74         if (!next)
75                 return;
76         os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
77         next->usage = 1;
78         next->clean = clean;
79         next->next = *dynamic_ifaces;
80         *dynamic_ifaces = next;
81 }
82
83
84 /* Decrement reference counter for given ifname.
85  * Return clean flag iff reference counter was decreased to zero, else zero
86  */
87 static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
88 {
89         struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
90         struct hapd_interfaces *interfaces;
91         int clean;
92
93         interfaces = hapd->iface->interfaces;
94         dynamic_ifaces = &interfaces->vlan_priv;
95
96         for (next = *dynamic_ifaces; next; next = next->next) {
97                 if (os_strcmp(ifname, next->ifname) == 0)
98                         break;
99                 prev = next;
100         }
101
102         if (!next)
103                 return 0;
104
105         next->usage--;
106         if (next->usage)
107                 return 0;
108
109         if (prev)
110                 prev->next = next->next;
111         else
112                 *dynamic_ifaces = next->next;
113         clean = next->clean;
114         os_free(next);
115
116         return clean;
117 }
118
119
120 static int ifconfig_down(const char *if_name)
121 {
122         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
123         return ifconfig_helper(if_name, 0);
124 }
125
126
127 /* This value should be 256 ONLY. If it is something else, then hostapd
128  * might crash!, as this value has been hard-coded in 2.4.x kernel
129  * bridging code.
130  */
131 #define MAX_BR_PORTS                    256
132
133 static int br_delif(const char *br_name, const char *if_name)
134 {
135         int fd;
136         struct ifreq ifr;
137         unsigned long args[2];
138         int if_index;
139
140         wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
141         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
142                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
143                            "failed: %s", __func__, strerror(errno));
144                 return -1;
145         }
146
147         if (linux_br_del_if(fd, br_name, if_name) == 0)
148                 goto done;
149
150         if_index = if_nametoindex(if_name);
151
152         if (if_index == 0) {
153                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
154                            "interface index for '%s'",
155                            __func__, if_name);
156                 close(fd);
157                 return -1;
158         }
159
160         args[0] = BRCTL_DEL_IF;
161         args[1] = if_index;
162
163         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
164         ifr.ifr_data = (void *) args;
165
166         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
167                 /* No error if interface already removed. */
168                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
169                            "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
170                            "%s", __func__, br_name, if_name, strerror(errno));
171                 close(fd);
172                 return -1;
173         }
174
175 done:
176         close(fd);
177         return 0;
178 }
179
180
181 /*
182         Add interface 'if_name' to the bridge 'br_name'
183
184         returns -1 on error
185         returns 1 if the interface is already part of the bridge
186         returns 0 otherwise
187 */
188 static int br_addif(const char *br_name, const char *if_name)
189 {
190         int fd;
191         struct ifreq ifr;
192         unsigned long args[2];
193         int if_index;
194
195         wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
196         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
197                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
198                            "failed: %s", __func__, strerror(errno));
199                 return -1;
200         }
201
202         if (linux_br_add_if(fd, br_name, if_name) == 0)
203                 goto done;
204         if (errno == EBUSY) {
205                 /* The interface is already added. */
206                 close(fd);
207                 return 1;
208         }
209
210         if_index = if_nametoindex(if_name);
211
212         if (if_index == 0) {
213                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
214                            "interface index for '%s'",
215                            __func__, if_name);
216                 close(fd);
217                 return -1;
218         }
219
220         args[0] = BRCTL_ADD_IF;
221         args[1] = if_index;
222
223         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
224         ifr.ifr_data = (void *) args;
225
226         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
227                 if (errno == EBUSY) {
228                         /* The interface is already added. */
229                         close(fd);
230                         return 1;
231                 }
232
233                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
234                            "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
235                            "%s", __func__, br_name, if_name, strerror(errno));
236                 close(fd);
237                 return -1;
238         }
239
240 done:
241         close(fd);
242         return 0;
243 }
244
245
246 static int br_delbr(const char *br_name)
247 {
248         int fd;
249         unsigned long arg[2];
250
251         wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
252         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
253                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
254                            "failed: %s", __func__, strerror(errno));
255                 return -1;
256         }
257
258         if (linux_br_del(fd, br_name) == 0)
259                 goto done;
260
261         arg[0] = BRCTL_DEL_BRIDGE;
262         arg[1] = (unsigned long) br_name;
263
264         if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
265                 /* No error if bridge already removed. */
266                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
267                            "%s: %s", __func__, br_name, strerror(errno));
268                 close(fd);
269                 return -1;
270         }
271
272 done:
273         close(fd);
274         return 0;
275 }
276
277
278 /*
279         Add a bridge with the name 'br_name'.
280
281         returns -1 on error
282         returns 1 if the bridge already exists
283         returns 0 otherwise
284 */
285 static int br_addbr(const char *br_name)
286 {
287         int fd;
288         unsigned long arg[4];
289         struct ifreq ifr;
290
291         wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
292         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
293                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
294                            "failed: %s", __func__, strerror(errno));
295                 return -1;
296         }
297
298         if (linux_br_add(fd, br_name) == 0)
299                 goto done;
300         if (errno == EEXIST) {
301                 /* The bridge is already added. */
302                 close(fd);
303                 return 1;
304         }
305
306         arg[0] = BRCTL_ADD_BRIDGE;
307         arg[1] = (unsigned long) br_name;
308
309         if (ioctl(fd, SIOCGIFBR, arg) < 0) {
310                 if (errno == EEXIST) {
311                         /* The bridge is already added. */
312                         close(fd);
313                         return 1;
314                 } else {
315                         wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
316                                    "failed for %s: %s",
317                                    __func__, br_name, strerror(errno));
318                         close(fd);
319                         return -1;
320                 }
321         }
322
323 done:
324         /* Decrease forwarding delay to avoid EAPOL timeouts. */
325         os_memset(&ifr, 0, sizeof(ifr));
326         os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
327         arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
328         arg[1] = 1;
329         arg[2] = 0;
330         arg[3] = 0;
331         ifr.ifr_data = (char *) &arg;
332         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
333                 wpa_printf(MSG_ERROR, "VLAN: %s: "
334                            "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
335                            "%s: %s", __func__, br_name, strerror(errno));
336                 /* Continue anyway */
337         }
338
339         close(fd);
340         return 0;
341 }
342
343
344 static int br_getnumports(const char *br_name)
345 {
346         int fd;
347         int i;
348         int port_cnt = 0;
349         unsigned long arg[4];
350         int ifindices[MAX_BR_PORTS];
351         struct ifreq ifr;
352
353         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
354                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
355                            "failed: %s", __func__, strerror(errno));
356                 return -1;
357         }
358
359         arg[0] = BRCTL_GET_PORT_LIST;
360         arg[1] = (unsigned long) ifindices;
361         arg[2] = MAX_BR_PORTS;
362         arg[3] = 0;
363
364         os_memset(ifindices, 0, sizeof(ifindices));
365         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
366         ifr.ifr_data = (void *) arg;
367
368         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
369                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
370                            "failed for %s: %s",
371                            __func__, br_name, strerror(errno));
372                 close(fd);
373                 return -1;
374         }
375
376         for (i = 1; i < MAX_BR_PORTS; i++) {
377                 if (ifindices[i] > 0) {
378                         port_cnt++;
379                 }
380         }
381
382         close(fd);
383         return port_cnt;
384 }
385
386
387 static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
388                                 const char *br_name, int vid,
389                                 struct hostapd_data *hapd)
390 {
391         char vlan_ifname[IFNAMSIZ];
392         int clean;
393         int ret;
394
395         if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
396                 ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
397                                   tagged_interface, vid);
398         else
399                 ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
400                                   vid);
401         if (ret >= (int) sizeof(vlan_ifname))
402                 wpa_printf(MSG_WARNING,
403                            "VLAN: Interface name was truncated to %s",
404                            vlan_ifname);
405
406         clean = 0;
407         ifconfig_up(tagged_interface);
408         if (!vlan_add(tagged_interface, vid, vlan_ifname))
409                 clean |= DVLAN_CLEAN_VLAN;
410
411         if (!br_addif(br_name, vlan_ifname))
412                 clean |= DVLAN_CLEAN_VLAN_PORT;
413
414         dyn_iface_get(hapd, vlan_ifname, clean);
415
416         ifconfig_up(vlan_ifname);
417 }
418
419
420 static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
421                              struct hostapd_vlan *vlan, int vid)
422 {
423         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
424         int ret;
425
426         if (vlan->bridge[0]) {
427                 os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
428                 ret = 0;
429         } else if (hapd->conf->vlan_bridge[0]) {
430                 ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
431                                   hapd->conf->vlan_bridge, vid);
432         } else if (tagged_interface) {
433                 ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
434                                   tagged_interface, vid);
435         } else {
436                 ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
437         }
438         if (ret >= IFNAMSIZ)
439                 wpa_printf(MSG_WARNING,
440                            "VLAN: Interface name was truncated to %s",
441                            br_name);
442 }
443
444
445 static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
446                             int vid)
447 {
448         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
449         int vlan_naming = hapd->conf->ssid.vlan_naming;
450
451         dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
452
453         ifconfig_up(br_name);
454
455         if (tagged_interface)
456                 vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
457                                     vid, hapd);
458 }
459
460
461 void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
462 {
463         char br_name[IFNAMSIZ];
464         struct hostapd_vlan *vlan;
465         int untagged, *tagged, i, notempty;
466
467         wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
468
469         for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
470                 if (vlan->configured ||
471                     os_strcmp(ifname, vlan->ifname) != 0)
472                         continue;
473                 break;
474         }
475         if (!vlan)
476                 return;
477
478         vlan->configured = 1;
479
480         notempty = vlan->vlan_desc.notempty;
481         untagged = vlan->vlan_desc.untagged;
482         tagged = vlan->vlan_desc.tagged;
483
484         if (!notempty) {
485                 /* Non-VLAN STA */
486                 if (hapd->conf->bridge[0] &&
487                     !br_addif(hapd->conf->bridge, ifname))
488                         vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
489         } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
490                 vlan_bridge_name(br_name, hapd, vlan, untagged);
491
492                 vlan_get_bridge(br_name, hapd, untagged);
493
494                 if (!br_addif(br_name, ifname))
495                         vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
496         }
497
498         for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
499                 if (tagged[i] == untagged ||
500                     tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
501                     (i > 0 && tagged[i] == tagged[i - 1]))
502                         continue;
503                 vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
504                 vlan_get_bridge(br_name, hapd, tagged[i]);
505                 vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
506                                     ifname, br_name, tagged[i], hapd);
507         }
508
509         ifconfig_up(ifname);
510 }
511
512
513 static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
514                                 const char *br_name, int vid,
515                                 struct hostapd_data *hapd)
516 {
517         char vlan_ifname[IFNAMSIZ];
518         int clean;
519         int ret;
520
521         if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
522                 ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
523                                   tagged_interface, vid);
524         else
525                 ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
526                                   vid);
527         if (ret >= (int) sizeof(vlan_ifname))
528                 wpa_printf(MSG_WARNING,
529                            "VLAN: Interface name was truncated to %s",
530                            vlan_ifname);
531
532
533         clean = dyn_iface_put(hapd, vlan_ifname);
534
535         if (clean & DVLAN_CLEAN_VLAN_PORT)
536                 br_delif(br_name, vlan_ifname);
537
538         if (clean & DVLAN_CLEAN_VLAN) {
539                 ifconfig_down(vlan_ifname);
540                 vlan_rem(vlan_ifname);
541         }
542 }
543
544
545 static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
546                             int vid)
547 {
548         int clean;
549         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
550         int vlan_naming = hapd->conf->ssid.vlan_naming;
551
552         if (tagged_interface)
553                 vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
554                                     vid, hapd);
555
556         clean = dyn_iface_put(hapd, br_name);
557         if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
558                 ifconfig_down(br_name);
559                 br_delbr(br_name);
560         }
561 }
562
563
564 void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
565 {
566         struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
567
568         wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
569
570         first = prev = vlan;
571
572         while (vlan) {
573                 if (os_strcmp(ifname, vlan->ifname) != 0) {
574                         prev = vlan;
575                         vlan = vlan->next;
576                         continue;
577                 }
578                 break;
579         }
580         if (!vlan)
581                 return;
582
583         if (vlan->configured) {
584                 int notempty = vlan->vlan_desc.notempty;
585                 int untagged = vlan->vlan_desc.untagged;
586                 int *tagged = vlan->vlan_desc.tagged;
587                 char br_name[IFNAMSIZ];
588                 int i;
589
590                 for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
591                         if (tagged[i] == untagged ||
592                             tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
593                             (i > 0 && tagged[i] == tagged[i - 1]))
594                                 continue;
595                         vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
596                         vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
597                                             ifname, br_name, tagged[i], hapd);
598                         vlan_put_bridge(br_name, hapd, tagged[i]);
599                 }
600
601                 if (!notempty) {
602                         /* Non-VLAN STA */
603                         if (hapd->conf->bridge[0] &&
604                             (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
605                                 br_delif(hapd->conf->bridge, ifname);
606                 } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
607                         vlan_bridge_name(br_name, hapd, vlan, untagged);
608
609                         if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
610                                 br_delif(br_name, vlan->ifname);
611
612                         vlan_put_bridge(br_name, hapd, untagged);
613                 }
614         }
615
616         /*
617          * Ensure this VLAN interface is actually removed even if
618          * NEWLINK message is only received later.
619          */
620         if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
621                 wpa_printf(MSG_ERROR,
622                            "VLAN: Could not remove VLAN iface: %s: %s",
623                            vlan->ifname, strerror(errno));
624
625         if (vlan == first)
626                 hapd->conf->vlan = vlan->next;
627         else
628                 prev->next = vlan->next;
629
630         os_free(vlan);
631 }
632
633
634 static void
635 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
636                   struct hostapd_data *hapd)
637 {
638         struct ifinfomsg *ifi;
639         int attrlen, nlmsg_len, rta_len;
640         struct rtattr *attr;
641         char ifname[IFNAMSIZ + 1];
642
643         if (len < sizeof(*ifi))
644                 return;
645
646         ifi = NLMSG_DATA(h);
647
648         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
649
650         attrlen = h->nlmsg_len - nlmsg_len;
651         if (attrlen < 0)
652                 return;
653
654         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
655
656         os_memset(ifname, 0, sizeof(ifname));
657         rta_len = RTA_ALIGN(sizeof(struct rtattr));
658         while (RTA_OK(attr, attrlen)) {
659                 if (attr->rta_type == IFLA_IFNAME) {
660                         int n = attr->rta_len - rta_len;
661                         if (n < 0)
662                                 break;
663
664                         if ((size_t) n >= sizeof(ifname))
665                                 n = sizeof(ifname) - 1;
666                         os_memcpy(ifname, ((char *) attr) + rta_len, n);
667
668                 }
669
670                 attr = RTA_NEXT(attr, attrlen);
671         }
672
673         if (!ifname[0])
674                 return;
675         if (del && if_nametoindex(ifname)) {
676                  /* interface still exists, race condition ->
677                   * iface has just been recreated */
678                 return;
679         }
680
681         wpa_printf(MSG_DEBUG,
682                    "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
683                    del ? "DEL" : "NEW",
684                    ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
685                    (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
686                    (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
687                    (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
688                    (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
689
690         if (del)
691                 vlan_dellink(ifname, hapd);
692         else
693                 vlan_newlink(ifname, hapd);
694 }
695
696
697 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
698 {
699         char buf[8192];
700         int left;
701         struct sockaddr_nl from;
702         socklen_t fromlen;
703         struct nlmsghdr *h;
704         struct hostapd_data *hapd = eloop_ctx;
705
706         fromlen = sizeof(from);
707         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
708                         (struct sockaddr *) &from, &fromlen);
709         if (left < 0) {
710                 if (errno != EINTR && errno != EAGAIN)
711                         wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
712                                    __func__, strerror(errno));
713                 return;
714         }
715
716         h = (struct nlmsghdr *) buf;
717         while (NLMSG_OK(h, left)) {
718                 int len, plen;
719
720                 len = h->nlmsg_len;
721                 plen = len - sizeof(*h);
722                 if (len > left || plen < 0) {
723                         wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
724                                    "message: len=%d left=%d plen=%d",
725                                    len, left, plen);
726                         break;
727                 }
728
729                 switch (h->nlmsg_type) {
730                 case RTM_NEWLINK:
731                         vlan_read_ifnames(h, plen, 0, hapd);
732                         break;
733                 case RTM_DELLINK:
734                         vlan_read_ifnames(h, plen, 1, hapd);
735                         break;
736                 }
737
738                 h = NLMSG_NEXT(h, left);
739         }
740
741         if (left > 0) {
742                 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
743                            "netlink message", __func__, left);
744         }
745 }
746
747
748 struct full_dynamic_vlan *
749 full_dynamic_vlan_init(struct hostapd_data *hapd)
750 {
751         struct sockaddr_nl local;
752         struct full_dynamic_vlan *priv;
753
754         priv = os_zalloc(sizeof(*priv));
755         if (priv == NULL)
756                 return NULL;
757
758         vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
759                            DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
760                            VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
761                            VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
762
763         priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
764         if (priv->s < 0) {
765                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
766                            "NETLINK_ROUTE) failed: %s",
767                            __func__, strerror(errno));
768                 os_free(priv);
769                 return NULL;
770         }
771
772         os_memset(&local, 0, sizeof(local));
773         local.nl_family = AF_NETLINK;
774         local.nl_groups = RTMGRP_LINK;
775         if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
776                 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
777                            __func__, strerror(errno));
778                 close(priv->s);
779                 os_free(priv);
780                 return NULL;
781         }
782
783         if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
784         {
785                 close(priv->s);
786                 os_free(priv);
787                 return NULL;
788         }
789
790         return priv;
791 }
792
793
794 void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
795 {
796         if (priv == NULL)
797                 return;
798         eloop_unregister_read_sock(priv->s);
799         close(priv->s);
800         os_free(priv);
801 }