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
31struct 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
39struct 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 */
50static 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 */
87static 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
120static 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
133static 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
175done:
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*/
188static 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
240done:
241	close(fd);
242	return 0;
243}
244
245
246static 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
272done:
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*/
285static 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
323done:
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
344static 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
387static 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
420static 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
445static 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
461void 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
513static 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
545static 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
564void 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
634static void
635vlan_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
697static 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
748struct full_dynamic_vlan *
749full_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
794void 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