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