vlan_init.c revision 214734
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
37struct full_dynamic_vlan {
38	int s; /* socket on which to listen for new/removed interfaces. */
39};
40
41
42static 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
82static 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
89static 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
109static 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*/
160static 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
209static 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*/
244static 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
294static 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
337static 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*/
380static 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
447static 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
477static 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
523static 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
574static void
575vlan_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
621static 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
674static struct full_dynamic_vlan *
675full_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
717static 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
728int 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
753static 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
779static 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
803int 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
816void 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
826struct 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
878int 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