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