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