xref: /netbsd/external/bsd/wpa/dist/src/ap/vlan_full.c (revision 0d69f216)
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  */
dyn_iface_get(struct hostapd_data * hapd,const char * ifname,int clean)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  */
dyn_iface_put(struct hostapd_data * hapd,const char * ifname)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 
ifconfig_down(const char * if_name)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 
br_delif(const char * br_name,const char * if_name)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 */
br_addif(const char * br_name,const char * if_name)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 
br_delbr(const char * br_name)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 */
br_addbr(const char * br_name)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 
br_getnumports(const char * br_name)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 
vlan_newlink_tagged(int vlan_naming,const char * tagged_interface,const char * br_name,int vid,struct hostapd_data * hapd)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 
vlan_bridge_name(char * br_name,struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vid)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 
vlan_get_bridge(const char * br_name,struct hostapd_data * hapd,int vid)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 
vlan_newlink(const char * ifname,struct hostapd_data * hapd)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 
vlan_dellink_tagged(int vlan_naming,const char * tagged_interface,const char * br_name,int vid,struct hostapd_data * hapd)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 
vlan_put_bridge(const char * br_name,struct hostapd_data * hapd,int vid)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 
vlan_dellink(const char * ifname,struct hostapd_data * hapd)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
vlan_read_ifnames(struct nlmsghdr * h,size_t len,int del,struct hostapd_data * hapd)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 
vlan_event_receive(int sock,void * eloop_ctx,void * sock_ctx)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 *
full_dynamic_vlan_init(struct hostapd_data * hapd)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 
full_dynamic_vlan_deinit(struct full_dynamic_vlan * priv)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 }
802