Home | History | Annotate | Download | only in ap
      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 (at) w1.fi>
      6  *
      7  * This software may be distributed under the terms of the BSD license.
      8  * See README for more details.
      9  */
     10 
     11 #include "utils/includes.h"
     12 #include <net/if.h>
     13 /* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
     14 #undef if_type
     15 #include <sys/ioctl.h>
     16 
     17 #include "utils/common.h"
     18 #include "drivers/priv_netlink.h"
     19 #include "drivers/linux_ioctl.h"
     20 #include "common/linux_bridge.h"
     21 #include "common/linux_vlan.h"
     22 #include "utils/eloop.h"
     23 #include "hostapd.h"
     24 #include "ap_config.h"
     25 #include "ap_drv_ops.h"
     26 #include "wpa_auth.h"
     27 #include "vlan_init.h"
     28 #include "vlan_util.h"
     29 
     30 
     31 struct full_dynamic_vlan {
     32 	int s; /* socket on which to listen for new/removed interfaces. */
     33 };
     34 
     35 #define DVLAN_CLEAN_BR         0x1
     36 #define DVLAN_CLEAN_VLAN       0x2
     37 #define DVLAN_CLEAN_VLAN_PORT  0x4
     38 
     39 struct dynamic_iface {
     40 	char ifname[IFNAMSIZ + 1];
     41 	int usage;
     42 	int clean;
     43 	struct dynamic_iface *next;
     44 };
     45 
     46 
     47 /* Increment ref counter for ifname and add clean flag.
     48  * If not in list, add it only if some flags are given.
     49  */
     50 static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
     51 			  int clean)
     52 {
     53 	struct dynamic_iface *next, **dynamic_ifaces;
     54 	struct hapd_interfaces *interfaces;
     55 
     56 	interfaces = hapd->iface->interfaces;
     57 	dynamic_ifaces = &interfaces->vlan_priv;
     58 
     59 	for (next = *dynamic_ifaces; next; next = next->next) {
     60 		if (os_strcmp(ifname, next->ifname) == 0)
     61 			break;
     62 	}
     63 
     64 	if (next) {
     65 		next->usage++;
     66 		next->clean |= clean;
     67 		return;
     68 	}
     69 
     70 	if (!clean)
     71 		return;
     72 
     73 	next = os_zalloc(sizeof(*next));
     74 	if (!next)
     75 		return;
     76 	os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
     77 	next->usage = 1;
     78 	next->clean = clean;
     79 	next->next = *dynamic_ifaces;
     80 	*dynamic_ifaces = next;
     81 }
     82 
     83 
     84 /* Decrement reference counter for given ifname.
     85  * Return clean flag iff reference counter was decreased to zero, else zero
     86  */
     87 static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
     88 {
     89 	struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
     90 	struct hapd_interfaces *interfaces;
     91 	int clean;
     92 
     93 	interfaces = hapd->iface->interfaces;
     94 	dynamic_ifaces = &interfaces->vlan_priv;
     95 
     96 	for (next = *dynamic_ifaces; next; next = next->next) {
     97 		if (os_strcmp(ifname, next->ifname) == 0)
     98 			break;
     99 		prev = next;
    100 	}
    101 
    102 	if (!next)
    103 		return 0;
    104 
    105 	next->usage--;
    106 	if (next->usage)
    107 		return 0;
    108 
    109 	if (prev)
    110 		prev->next = next->next;
    111 	else
    112 		*dynamic_ifaces = next->next;
    113 	clean = next->clean;
    114 	os_free(next);
    115 
    116 	return clean;
    117 }
    118 
    119 
    120 static int ifconfig_down(const char *if_name)
    121 {
    122 	wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
    123 	return ifconfig_helper(if_name, 0);
    124 }
    125 
    126 
    127 /* This value should be 256 ONLY. If it is something else, then hostapd
    128  * might crash!, as this value has been hard-coded in 2.4.x kernel
    129  * bridging code.
    130  */
    131 #define MAX_BR_PORTS      		256
    132 
    133 static int br_delif(const char *br_name, const char *if_name)
    134 {
    135 	int fd;
    136 	struct ifreq ifr;
    137 	unsigned long args[2];
    138 	int if_index;
    139 
    140 	wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
    141 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    142 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
    143 			   "failed: %s", __func__, strerror(errno));
    144 		return -1;
    145 	}
    146 
    147 	if (linux_br_del_if(fd, br_name, if_name) == 0)
    148 		goto done;
    149 
    150 	if_index = if_nametoindex(if_name);
    151 
    152 	if (if_index == 0) {
    153 		wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
    154 			   "interface index for '%s'",
    155 			   __func__, if_name);
    156 		close(fd);
    157 		return -1;
    158 	}
    159 
    160 	args[0] = BRCTL_DEL_IF;
    161 	args[1] = if_index;
    162 
    163 	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
    164 	ifr.ifr_data = (void *) args;
    165 
    166 	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
    167 		/* No error if interface already removed. */
    168 		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
    169 			   "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
    170 			   "%s", __func__, br_name, if_name, strerror(errno));
    171 		close(fd);
    172 		return -1;
    173 	}
    174 
    175 done:
    176 	close(fd);
    177 	return 0;
    178 }
    179 
    180 
    181 /*
    182 	Add interface 'if_name' to the bridge 'br_name'
    183 
    184 	returns -1 on error
    185 	returns 1 if the interface is already part of the bridge
    186 	returns 0 otherwise
    187 */
    188 static int br_addif(const char *br_name, const char *if_name)
    189 {
    190 	int fd;
    191 	struct ifreq ifr;
    192 	unsigned long args[2];
    193 	int if_index;
    194 
    195 	wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
    196 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    197 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
    198 			   "failed: %s", __func__, strerror(errno));
    199 		return -1;
    200 	}
    201 
    202 	if (linux_br_add_if(fd, br_name, if_name) == 0)
    203 		goto done;
    204 	if (errno == EBUSY) {
    205 		/* The interface is already added. */
    206 		close(fd);
    207 		return 1;
    208 	}
    209 
    210 	if_index = if_nametoindex(if_name);
    211 
    212 	if (if_index == 0) {
    213 		wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
    214 			   "interface index for '%s'",
    215 			   __func__, if_name);
    216 		close(fd);
    217 		return -1;
    218 	}
    219 
    220 	args[0] = BRCTL_ADD_IF;
    221 	args[1] = if_index;
    222 
    223 	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
    224 	ifr.ifr_data = (void *) args;
    225 
    226 	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
    227 		if (errno == EBUSY) {
    228 			/* The interface is already added. */
    229 			close(fd);
    230 			return 1;
    231 		}
    232 
    233 		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
    234 			   "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
    235 			   "%s", __func__, br_name, if_name, strerror(errno));
    236 		close(fd);
    237 		return -1;
    238 	}
    239 
    240 done:
    241 	close(fd);
    242 	return 0;
    243 }
    244 
    245 
    246 static int br_delbr(const char *br_name)
    247 {
    248 	int fd;
    249 	unsigned long arg[2];
    250 
    251 	wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
    252 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    253 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
    254 			   "failed: %s", __func__, strerror(errno));
    255 		return -1;
    256 	}
    257 
    258 	if (linux_br_del(fd, br_name) == 0)
    259 		goto done;
    260 
    261 	arg[0] = BRCTL_DEL_BRIDGE;
    262 	arg[1] = (unsigned long) br_name;
    263 
    264 	if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
    265 		/* No error if bridge already removed. */
    266 		wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
    267 			   "%s: %s", __func__, br_name, strerror(errno));
    268 		close(fd);
    269 		return -1;
    270 	}
    271 
    272 done:
    273 	close(fd);
    274 	return 0;
    275 }
    276 
    277 
    278 /*
    279 	Add a bridge with the name 'br_name'.
    280 
    281 	returns -1 on error
    282 	returns 1 if the bridge already exists
    283 	returns 0 otherwise
    284 */
    285 static int br_addbr(const char *br_name)
    286 {
    287 	int fd;
    288 	unsigned long arg[4];
    289 	struct ifreq ifr;
    290 
    291 	wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
    292 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    293 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
    294 			   "failed: %s", __func__, strerror(errno));
    295 		return -1;
    296 	}
    297 
    298 	if (linux_br_add(fd, br_name) == 0)
    299 		goto done;
    300 	if (errno == EEXIST) {
    301 		/* The bridge is already added. */
    302 		close(fd);
    303 		return 1;
    304 	}
    305 
    306 	arg[0] = BRCTL_ADD_BRIDGE;
    307 	arg[1] = (unsigned long) br_name;
    308 
    309 	if (ioctl(fd, SIOCGIFBR, arg) < 0) {
    310 		if (errno == EEXIST) {
    311 			/* The bridge is already added. */
    312 			close(fd);
    313 			return 1;
    314 		} else {
    315 			wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
    316 				   "failed for %s: %s",
    317 				   __func__, br_name, strerror(errno));
    318 			close(fd);
    319 			return -1;
    320 		}
    321 	}
    322 
    323 done:
    324 	/* Decrease forwarding delay to avoid EAPOL timeouts. */
    325 	os_memset(&ifr, 0, sizeof(ifr));
    326 	os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
    327 	arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
    328 	arg[1] = 1;
    329 	arg[2] = 0;
    330 	arg[3] = 0;
    331 	ifr.ifr_data = (char *) &arg;
    332 	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
    333 		wpa_printf(MSG_ERROR, "VLAN: %s: "
    334 			   "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
    335 			   "%s: %s", __func__, br_name, strerror(errno));
    336 		/* Continue anyway */
    337 	}
    338 
    339 	close(fd);
    340 	return 0;
    341 }
    342 
    343 
    344 static int br_getnumports(const char *br_name)
    345 {
    346 	int fd;
    347 	int i;
    348 	int port_cnt = 0;
    349 	unsigned long arg[4];
    350 	int ifindices[MAX_BR_PORTS];
    351 	struct ifreq ifr;
    352 
    353 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    354 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
    355 			   "failed: %s", __func__, strerror(errno));
    356 		return -1;
    357 	}
    358 
    359 	arg[0] = BRCTL_GET_PORT_LIST;
    360 	arg[1] = (unsigned long) ifindices;
    361 	arg[2] = MAX_BR_PORTS;
    362 	arg[3] = 0;
    363 
    364 	os_memset(ifindices, 0, sizeof(ifindices));
    365 	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
    366 	ifr.ifr_data = (void *) arg;
    367 
    368 	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
    369 		wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
    370 			   "failed for %s: %s",
    371 			   __func__, br_name, strerror(errno));
    372 		close(fd);
    373 		return -1;
    374 	}
    375 
    376 	for (i = 1; i < MAX_BR_PORTS; i++) {
    377 		if (ifindices[i] > 0) {
    378 			port_cnt++;
    379 		}
    380 	}
    381 
    382 	close(fd);
    383 	return port_cnt;
    384 }
    385 
    386 
    387 static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
    388 				const char *br_name, int vid,
    389 				struct hostapd_data *hapd)
    390 {
    391 	char vlan_ifname[IFNAMSIZ];
    392 	int clean;
    393 	int ret;
    394 
    395 	if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
    396 		ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
    397 				  tagged_interface, vid);
    398 	else
    399 		ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
    400 				  vid);
    401 	if (ret >= (int) sizeof(vlan_ifname))
    402 		wpa_printf(MSG_WARNING,
    403 			   "VLAN: Interface name was truncated to %s",
    404 			   vlan_ifname);
    405 
    406 	clean = 0;
    407 	ifconfig_up(tagged_interface);
    408 	if (!vlan_add(tagged_interface, vid, vlan_ifname))
    409 		clean |= DVLAN_CLEAN_VLAN;
    410 
    411 	if (!br_addif(br_name, vlan_ifname))
    412 		clean |= DVLAN_CLEAN_VLAN_PORT;
    413 
    414 	dyn_iface_get(hapd, vlan_ifname, clean);
    415 
    416 	ifconfig_up(vlan_ifname);
    417 }
    418 
    419 
    420 static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
    421 			     struct hostapd_vlan *vlan, int vid)
    422 {
    423 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
    424 	int ret;
    425 
    426 	if (vlan->bridge[0]) {
    427 		os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
    428 		ret = 0;
    429 	} else if (hapd->conf->vlan_bridge[0]) {
    430 		ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
    431 				  hapd->conf->vlan_bridge, vid);
    432 	} else if (tagged_interface) {
    433 		ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
    434 				  tagged_interface, vid);
    435 	} else {
    436 		ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
    437 	}
    438 	if (ret >= IFNAMSIZ)
    439 		wpa_printf(MSG_WARNING,
    440 			   "VLAN: Interface name was truncated to %s",
    441 			   br_name);
    442 }
    443 
    444 
    445 static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
    446 			    int vid)
    447 {
    448 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
    449 	int vlan_naming = hapd->conf->ssid.vlan_naming;
    450 
    451 	dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
    452 
    453 	ifconfig_up(br_name);
    454 
    455 	if (tagged_interface)
    456 		vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
    457 				    vid, hapd);
    458 }
    459 
    460 
    461 void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
    462 {
    463 	char br_name[IFNAMSIZ];
    464 	struct hostapd_vlan *vlan;
    465 	int untagged, *tagged, i, notempty;
    466 
    467 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
    468 
    469 	for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
    470 		if (vlan->configured ||
    471 		    os_strcmp(ifname, vlan->ifname) != 0)
    472 			continue;
    473 		break;
    474 	}
    475 	if (!vlan)
    476 		return;
    477 
    478 	vlan->configured = 1;
    479 
    480 	notempty = vlan->vlan_desc.notempty;
    481 	untagged = vlan->vlan_desc.untagged;
    482 	tagged = vlan->vlan_desc.tagged;
    483 
    484 	if (!notempty) {
    485 		/* Non-VLAN STA */
    486 		if (hapd->conf->bridge[0] &&
    487 		    !br_addif(hapd->conf->bridge, ifname))
    488 			vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
    489 	} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
    490 		vlan_bridge_name(br_name, hapd, vlan, untagged);
    491 
    492 		vlan_get_bridge(br_name, hapd, untagged);
    493 
    494 		if (!br_addif(br_name, ifname))
    495 			vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
    496 	}
    497 
    498 	for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
    499 		if (tagged[i] == untagged ||
    500 		    tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
    501 		    (i > 0 && tagged[i] == tagged[i - 1]))
    502 			continue;
    503 		vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
    504 		vlan_get_bridge(br_name, hapd, tagged[i]);
    505 		vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
    506 				    ifname, br_name, tagged[i], hapd);
    507 	}
    508 
    509 	ifconfig_up(ifname);
    510 }
    511 
    512 
    513 static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
    514 				const char *br_name, int vid,
    515 				struct hostapd_data *hapd)
    516 {
    517 	char vlan_ifname[IFNAMSIZ];
    518 	int clean;
    519 	int ret;
    520 
    521 	if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
    522 		ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
    523 				  tagged_interface, vid);
    524 	else
    525 		ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
    526 				  vid);
    527 	if (ret >= (int) sizeof(vlan_ifname))
    528 		wpa_printf(MSG_WARNING,
    529 			   "VLAN: Interface name was truncated to %s",
    530 			   vlan_ifname);
    531 
    532 
    533 	clean = dyn_iface_put(hapd, vlan_ifname);
    534 
    535 	if (clean & DVLAN_CLEAN_VLAN_PORT)
    536 		br_delif(br_name, vlan_ifname);
    537 
    538 	if (clean & DVLAN_CLEAN_VLAN) {
    539 		ifconfig_down(vlan_ifname);
    540 		vlan_rem(vlan_ifname);
    541 	}
    542 }
    543 
    544 
    545 static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
    546 			    int vid)
    547 {
    548 	int clean;
    549 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
    550 	int vlan_naming = hapd->conf->ssid.vlan_naming;
    551 
    552 	if (tagged_interface)
    553 		vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
    554 				    vid, hapd);
    555 
    556 	clean = dyn_iface_put(hapd, br_name);
    557 	if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
    558 		ifconfig_down(br_name);
    559 		br_delbr(br_name);
    560 	}
    561 }
    562 
    563 
    564 void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
    565 {
    566 	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
    567 
    568 	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
    569 
    570 	first = prev = vlan;
    571 
    572 	while (vlan) {
    573 		if (os_strcmp(ifname, vlan->ifname) != 0) {
    574 			prev = vlan;
    575 			vlan = vlan->next;
    576 			continue;
    577 		}
    578 		break;
    579 	}
    580 	if (!vlan)
    581 		return;
    582 
    583 	if (vlan->configured) {
    584 		int notempty = vlan->vlan_desc.notempty;
    585 		int untagged = vlan->vlan_desc.untagged;
    586 		int *tagged = vlan->vlan_desc.tagged;
    587 		char br_name[IFNAMSIZ];
    588 		int i;
    589 
    590 		for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
    591 			if (tagged[i] == untagged ||
    592 			    tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
    593 			    (i > 0 && tagged[i] == tagged[i - 1]))
    594 				continue;
    595 			vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
    596 			vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
    597 					    ifname, br_name, tagged[i], hapd);
    598 			vlan_put_bridge(br_name, hapd, tagged[i]);
    599 		}
    600 
    601 		if (!notempty) {
    602 			/* Non-VLAN STA */
    603 			if (hapd->conf->bridge[0] &&
    604 			    (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
    605 				br_delif(hapd->conf->bridge, ifname);
    606 		} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
    607 			vlan_bridge_name(br_name, hapd, vlan, untagged);
    608 
    609 			if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
    610 				br_delif(br_name, vlan->ifname);
    611 
    612 			vlan_put_bridge(br_name, hapd, untagged);
    613 		}
    614 	}
    615 
    616 	/*
    617 	 * Ensure this VLAN interface is actually removed even if
    618 	 * NEWLINK message is only received later.
    619 	 */
    620 	if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
    621 		wpa_printf(MSG_ERROR,
    622 			   "VLAN: Could not remove VLAN iface: %s: %s",
    623 			   vlan->ifname, strerror(errno));
    624 
    625 	if (vlan == first)
    626 		hapd->conf->vlan = vlan->next;
    627 	else
    628 		prev->next = vlan->next;
    629 
    630 	os_free(vlan);
    631 }
    632 
    633 
    634 static void
    635 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
    636 		  struct hostapd_data *hapd)
    637 {
    638 	struct ifinfomsg *ifi;
    639 	int attrlen, nlmsg_len, rta_len;
    640 	struct rtattr *attr;
    641 	char ifname[IFNAMSIZ + 1];
    642 
    643 	if (len < sizeof(*ifi))
    644 		return;
    645 
    646 	ifi = NLMSG_DATA(h);
    647 
    648 	nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
    649 
    650 	attrlen = h->nlmsg_len - nlmsg_len;
    651 	if (attrlen < 0)
    652 		return;
    653 
    654 	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
    655 
    656 	os_memset(ifname, 0, sizeof(ifname));
    657 	rta_len = RTA_ALIGN(sizeof(struct rtattr));
    658 	while (RTA_OK(attr, attrlen)) {
    659 		if (attr->rta_type == IFLA_IFNAME) {
    660 			int n = attr->rta_len - rta_len;
    661 			if (n < 0)
    662 				break;
    663 
    664 			if ((size_t) n >= sizeof(ifname))
    665 				n = sizeof(ifname) - 1;
    666 			os_memcpy(ifname, ((char *) attr) + rta_len, n);
    667 
    668 		}
    669 
    670 		attr = RTA_NEXT(attr, attrlen);
    671 	}
    672 
    673 	if (!ifname[0])
    674 		return;
    675 	if (del && if_nametoindex(ifname)) {
    676 		 /* interface still exists, race condition ->
    677 		  * iface has just been recreated */
    678 		return;
    679 	}
    680 
    681 	wpa_printf(MSG_DEBUG,
    682 		   "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
    683 		   del ? "DEL" : "NEW",
    684 		   ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
    685 		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
    686 		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
    687 		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
    688 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
    689 
    690 	if (del)
    691 		vlan_dellink(ifname, hapd);
    692 	else
    693 		vlan_newlink(ifname, hapd);
    694 }
    695 
    696 
    697 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
    698 {
    699 	char buf[8192];
    700 	int left;
    701 	struct sockaddr_nl from;
    702 	socklen_t fromlen;
    703 	struct nlmsghdr *h;
    704 	struct hostapd_data *hapd = eloop_ctx;
    705 
    706 	fromlen = sizeof(from);
    707 	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
    708 			(struct sockaddr *) &from, &fromlen);
    709 	if (left < 0) {
    710 		if (errno != EINTR && errno != EAGAIN)
    711 			wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
    712 				   __func__, strerror(errno));
    713 		return;
    714 	}
    715 
    716 	h = (struct nlmsghdr *) buf;
    717 	while (NLMSG_OK(h, left)) {
    718 		int len, plen;
    719 
    720 		len = h->nlmsg_len;
    721 		plen = len - sizeof(*h);
    722 		if (len > left || plen < 0) {
    723 			wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
    724 				   "message: len=%d left=%d plen=%d",
    725 				   len, left, plen);
    726 			break;
    727 		}
    728 
    729 		switch (h->nlmsg_type) {
    730 		case RTM_NEWLINK:
    731 			vlan_read_ifnames(h, plen, 0, hapd);
    732 			break;
    733 		case RTM_DELLINK:
    734 			vlan_read_ifnames(h, plen, 1, hapd);
    735 			break;
    736 		}
    737 
    738 		h = NLMSG_NEXT(h, left);
    739 	}
    740 
    741 	if (left > 0) {
    742 		wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
    743 			   "netlink message", __func__, left);
    744 	}
    745 }
    746 
    747 
    748 struct full_dynamic_vlan *
    749 full_dynamic_vlan_init(struct hostapd_data *hapd)
    750 {
    751 	struct sockaddr_nl local;
    752 	struct full_dynamic_vlan *priv;
    753 
    754 	priv = os_zalloc(sizeof(*priv));
    755 	if (priv == NULL)
    756 		return NULL;
    757 
    758 	vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
    759 			   DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
    760 			   VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
    761 			   VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
    762 
    763 	priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    764 	if (priv->s < 0) {
    765 		wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
    766 			   "NETLINK_ROUTE) failed: %s",
    767 			   __func__, strerror(errno));
    768 		os_free(priv);
    769 		return NULL;
    770 	}
    771 
    772 	os_memset(&local, 0, sizeof(local));
    773 	local.nl_family = AF_NETLINK;
    774 	local.nl_groups = RTMGRP_LINK;
    775 	if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
    776 		wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
    777 			   __func__, strerror(errno));
    778 		close(priv->s);
    779 		os_free(priv);
    780 		return NULL;
    781 	}
    782 
    783 	if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
    784 	{
    785 		close(priv->s);
    786 		os_free(priv);
    787 		return NULL;
    788 	}
    789 
    790 	return priv;
    791 }
    792 
    793 
    794 void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
    795 {
    796 	if (priv == NULL)
    797 		return;
    798 	eloop_unregister_read_sock(priv->s);
    799 	close(priv->s);
    800 	os_free(priv);
    801 }
    802