1214501Srpaulo/* 2214501Srpaulo * hostapd / VLAN initialization 3214501Srpaulo * Copyright 2003, Instant802 Networks, Inc. 4214501Srpaulo * Copyright 2005-2006, Devicescape Software, Inc. 5214501Srpaulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 6214501Srpaulo * 7214501Srpaulo * This program is free software; you can redistribute it and/or modify 8214501Srpaulo * it under the terms of the GNU General Public License version 2 as 9214501Srpaulo * published by the Free Software Foundation. 10214501Srpaulo * 11214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 12214501Srpaulo * license. 13214501Srpaulo * 14214501Srpaulo * See README and COPYING for more details. 15214501Srpaulo */ 16214501Srpaulo 17214501Srpaulo#include "utils/includes.h" 18214501Srpaulo 19214501Srpaulo#include "utils/common.h" 20214501Srpaulo#include "hostapd.h" 21214501Srpaulo#include "ap_config.h" 22214501Srpaulo#include "vlan_init.h" 23214501Srpaulo 24214501Srpaulo 25214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 26214501Srpaulo 27214501Srpaulo#include <net/if.h> 28214501Srpaulo#include <sys/ioctl.h> 29214501Srpaulo#include <linux/sockios.h> 30214501Srpaulo#include <linux/if_vlan.h> 31214501Srpaulo#include <linux/if_bridge.h> 32214501Srpaulo 33214501Srpaulo#include "drivers/priv_netlink.h" 34214501Srpaulo#include "utils/eloop.h" 35214501Srpaulo 36214501Srpaulo 37214501Srpaulostruct full_dynamic_vlan { 38214501Srpaulo int s; /* socket on which to listen for new/removed interfaces. */ 39214501Srpaulo}; 40214501Srpaulo 41214501Srpaulo 42214501Srpaulostatic int ifconfig_helper(const char *if_name, int up) 43214501Srpaulo{ 44214501Srpaulo int fd; 45214501Srpaulo struct ifreq ifr; 46214501Srpaulo 47214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 48214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 49214501Srpaulo "failed: %s", __func__, strerror(errno)); 50214501Srpaulo return -1; 51214501Srpaulo } 52214501Srpaulo 53214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 54214501Srpaulo os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); 55214501Srpaulo 56214501Srpaulo if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { 57214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed " 58214501Srpaulo "for interface %s: %s", 59214501Srpaulo __func__, if_name, strerror(errno)); 60214501Srpaulo close(fd); 61214501Srpaulo return -1; 62214501Srpaulo } 63214501Srpaulo 64214501Srpaulo if (up) 65214501Srpaulo ifr.ifr_flags |= IFF_UP; 66214501Srpaulo else 67214501Srpaulo ifr.ifr_flags &= ~IFF_UP; 68214501Srpaulo 69214501Srpaulo if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) { 70214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed " 71214501Srpaulo "for interface %s (up=%d): %s", 72214501Srpaulo __func__, if_name, up, strerror(errno)); 73214501Srpaulo close(fd); 74214501Srpaulo return -1; 75214501Srpaulo } 76214501Srpaulo 77214501Srpaulo close(fd); 78214501Srpaulo return 0; 79214501Srpaulo} 80214501Srpaulo 81214501Srpaulo 82214501Srpaulostatic int ifconfig_up(const char *if_name) 83214501Srpaulo{ 84214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name); 85214501Srpaulo return ifconfig_helper(if_name, 1); 86214501Srpaulo} 87214501Srpaulo 88214501Srpaulo 89214501Srpaulostatic int ifconfig_down(const char *if_name) 90214501Srpaulo{ 91214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name); 92214501Srpaulo return ifconfig_helper(if_name, 0); 93214501Srpaulo} 94214501Srpaulo 95214501Srpaulo 96214501Srpaulo/* 97214501Srpaulo * These are only available in recent linux headers (without the leading 98214501Srpaulo * underscore). 99214501Srpaulo */ 100214501Srpaulo#define _GET_VLAN_REALDEV_NAME_CMD 8 101214501Srpaulo#define _GET_VLAN_VID_CMD 9 102214501Srpaulo 103214501Srpaulo/* This value should be 256 ONLY. If it is something else, then hostapd 104214501Srpaulo * might crash!, as this value has been hard-coded in 2.4.x kernel 105214501Srpaulo * bridging code. 106214501Srpaulo */ 107214501Srpaulo#define MAX_BR_PORTS 256 108214501Srpaulo 109214501Srpaulostatic int br_delif(const char *br_name, const char *if_name) 110214501Srpaulo{ 111214501Srpaulo int fd; 112214501Srpaulo struct ifreq ifr; 113214501Srpaulo unsigned long args[2]; 114214501Srpaulo int if_index; 115214501Srpaulo 116214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name); 117214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 118214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 119214501Srpaulo "failed: %s", __func__, strerror(errno)); 120214501Srpaulo return -1; 121214501Srpaulo } 122214501Srpaulo 123214501Srpaulo if_index = if_nametoindex(if_name); 124214501Srpaulo 125214501Srpaulo if (if_index == 0) { 126214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " 127214501Srpaulo "interface index for '%s'", 128214501Srpaulo __func__, if_name); 129214501Srpaulo close(fd); 130214501Srpaulo return -1; 131214501Srpaulo } 132214501Srpaulo 133214501Srpaulo args[0] = BRCTL_DEL_IF; 134214501Srpaulo args[1] = if_index; 135214501Srpaulo 136214501Srpaulo os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 137214501Srpaulo ifr.ifr_data = (__caddr_t) args; 138214501Srpaulo 139214501Srpaulo if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) { 140214501Srpaulo /* No error if interface already removed. */ 141214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," 142214501Srpaulo "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: " 143214501Srpaulo "%s", __func__, br_name, if_name, strerror(errno)); 144214501Srpaulo close(fd); 145214501Srpaulo return -1; 146214501Srpaulo } 147214501Srpaulo 148214501Srpaulo close(fd); 149214501Srpaulo return 0; 150214501Srpaulo} 151214501Srpaulo 152214501Srpaulo 153214501Srpaulo/* 154214501Srpaulo Add interface 'if_name' to the bridge 'br_name' 155214501Srpaulo 156214501Srpaulo returns -1 on error 157214501Srpaulo returns 1 if the interface is already part of the bridge 158214501Srpaulo returns 0 otherwise 159214501Srpaulo*/ 160214501Srpaulostatic int br_addif(const char *br_name, const char *if_name) 161214501Srpaulo{ 162214501Srpaulo int fd; 163214501Srpaulo struct ifreq ifr; 164214501Srpaulo unsigned long args[2]; 165214501Srpaulo int if_index; 166214501Srpaulo 167214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name); 168214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 169214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 170214501Srpaulo "failed: %s", __func__, strerror(errno)); 171214501Srpaulo return -1; 172214501Srpaulo } 173214501Srpaulo 174214501Srpaulo if_index = if_nametoindex(if_name); 175214501Srpaulo 176214501Srpaulo if (if_index == 0) { 177214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " 178214501Srpaulo "interface index for '%s'", 179214501Srpaulo __func__, if_name); 180214501Srpaulo close(fd); 181214501Srpaulo return -1; 182214501Srpaulo } 183214501Srpaulo 184214501Srpaulo args[0] = BRCTL_ADD_IF; 185214501Srpaulo args[1] = if_index; 186214501Srpaulo 187214501Srpaulo os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 188214501Srpaulo ifr.ifr_data = (__caddr_t) args; 189214501Srpaulo 190214501Srpaulo if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 191214501Srpaulo if (errno == EBUSY) { 192214501Srpaulo /* The interface is already added. */ 193214501Srpaulo close(fd); 194214501Srpaulo return 1; 195214501Srpaulo } 196214501Srpaulo 197214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," 198214501Srpaulo "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: " 199214501Srpaulo "%s", __func__, br_name, if_name, strerror(errno)); 200214501Srpaulo close(fd); 201214501Srpaulo return -1; 202214501Srpaulo } 203214501Srpaulo 204214501Srpaulo close(fd); 205214501Srpaulo return 0; 206214501Srpaulo} 207214501Srpaulo 208214501Srpaulo 209214501Srpaulostatic int br_delbr(const char *br_name) 210214501Srpaulo{ 211214501Srpaulo int fd; 212214501Srpaulo unsigned long arg[2]; 213214501Srpaulo 214214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name); 215214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 216214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 217214501Srpaulo "failed: %s", __func__, strerror(errno)); 218214501Srpaulo return -1; 219214501Srpaulo } 220214501Srpaulo 221214501Srpaulo arg[0] = BRCTL_DEL_BRIDGE; 222214501Srpaulo arg[1] = (unsigned long) br_name; 223214501Srpaulo 224214501Srpaulo if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) { 225214501Srpaulo /* No error if bridge already removed. */ 226214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for " 227214501Srpaulo "%s: %s", __func__, br_name, strerror(errno)); 228214501Srpaulo close(fd); 229214501Srpaulo return -1; 230214501Srpaulo } 231214501Srpaulo 232214501Srpaulo close(fd); 233214501Srpaulo return 0; 234214501Srpaulo} 235214501Srpaulo 236214501Srpaulo 237214501Srpaulo/* 238214501Srpaulo Add a bridge with the name 'br_name'. 239214501Srpaulo 240214501Srpaulo returns -1 on error 241214501Srpaulo returns 1 if the bridge already exists 242214501Srpaulo returns 0 otherwise 243214501Srpaulo*/ 244214501Srpaulostatic int br_addbr(const char *br_name) 245214501Srpaulo{ 246214501Srpaulo int fd; 247214501Srpaulo unsigned long arg[4]; 248214501Srpaulo struct ifreq ifr; 249214501Srpaulo 250214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name); 251214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 252214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 253214501Srpaulo "failed: %s", __func__, strerror(errno)); 254214501Srpaulo return -1; 255214501Srpaulo } 256214501Srpaulo 257214501Srpaulo arg[0] = BRCTL_ADD_BRIDGE; 258214501Srpaulo arg[1] = (unsigned long) br_name; 259214501Srpaulo 260214501Srpaulo if (ioctl(fd, SIOCGIFBR, arg) < 0) { 261214501Srpaulo if (errno == EEXIST) { 262214501Srpaulo /* The bridge is already added. */ 263214501Srpaulo close(fd); 264214501Srpaulo return 1; 265214501Srpaulo } else { 266214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE " 267214501Srpaulo "failed for %s: %s", 268214501Srpaulo __func__, br_name, strerror(errno)); 269214501Srpaulo close(fd); 270214501Srpaulo return -1; 271214501Srpaulo } 272214501Srpaulo } 273214501Srpaulo 274214501Srpaulo /* Decrease forwarding delay to avoid EAPOL timeouts. */ 275214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 276214501Srpaulo os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ); 277214501Srpaulo arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; 278214501Srpaulo arg[1] = 1; 279214501Srpaulo arg[2] = 0; 280214501Srpaulo arg[3] = 0; 281214501Srpaulo ifr.ifr_data = (char *) &arg; 282214501Srpaulo if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 283214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: " 284214501Srpaulo "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for " 285214501Srpaulo "%s: %s", __func__, br_name, strerror(errno)); 286214501Srpaulo /* Continue anyway */ 287214501Srpaulo } 288214501Srpaulo 289214501Srpaulo close(fd); 290214501Srpaulo return 0; 291214501Srpaulo} 292214501Srpaulo 293214501Srpaulo 294214501Srpaulostatic int br_getnumports(const char *br_name) 295214501Srpaulo{ 296214501Srpaulo int fd; 297214501Srpaulo int i; 298214501Srpaulo int port_cnt = 0; 299214501Srpaulo unsigned long arg[4]; 300214501Srpaulo int ifindices[MAX_BR_PORTS]; 301214501Srpaulo struct ifreq ifr; 302214501Srpaulo 303214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 304214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 305214501Srpaulo "failed: %s", __func__, strerror(errno)); 306214501Srpaulo return -1; 307214501Srpaulo } 308214501Srpaulo 309214501Srpaulo arg[0] = BRCTL_GET_PORT_LIST; 310214501Srpaulo arg[1] = (unsigned long) ifindices; 311214501Srpaulo arg[2] = MAX_BR_PORTS; 312214501Srpaulo arg[3] = 0; 313214501Srpaulo 314214501Srpaulo os_memset(ifindices, 0, sizeof(ifindices)); 315214501Srpaulo os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 316214501Srpaulo ifr.ifr_data = (__caddr_t) arg; 317214501Srpaulo 318214501Srpaulo if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 319214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST " 320214501Srpaulo "failed for %s: %s", 321214501Srpaulo __func__, br_name, strerror(errno)); 322214501Srpaulo close(fd); 323214501Srpaulo return -1; 324214501Srpaulo } 325214501Srpaulo 326214501Srpaulo for (i = 1; i < MAX_BR_PORTS; i++) { 327214501Srpaulo if (ifindices[i] > 0) { 328214501Srpaulo port_cnt++; 329214501Srpaulo } 330214501Srpaulo } 331214501Srpaulo 332214501Srpaulo close(fd); 333214501Srpaulo return port_cnt; 334214501Srpaulo} 335214501Srpaulo 336214501Srpaulo 337214501Srpaulostatic int vlan_rem(const char *if_name) 338214501Srpaulo{ 339214501Srpaulo int fd; 340214501Srpaulo struct vlan_ioctl_args if_request; 341214501Srpaulo 342214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); 343214501Srpaulo if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 344214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 345214501Srpaulo if_name); 346214501Srpaulo return -1; 347214501Srpaulo } 348214501Srpaulo 349214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 350214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 351214501Srpaulo "failed: %s", __func__, strerror(errno)); 352214501Srpaulo return -1; 353214501Srpaulo } 354214501Srpaulo 355214501Srpaulo os_memset(&if_request, 0, sizeof(if_request)); 356214501Srpaulo 357214501Srpaulo os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 358214501Srpaulo if_request.cmd = DEL_VLAN_CMD; 359214501Srpaulo 360214501Srpaulo if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 361214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " 362214501Srpaulo "%s", __func__, if_name, strerror(errno)); 363214501Srpaulo close(fd); 364214501Srpaulo return -1; 365214501Srpaulo } 366214501Srpaulo 367214501Srpaulo close(fd); 368214501Srpaulo return 0; 369214501Srpaulo} 370214501Srpaulo 371214501Srpaulo 372214501Srpaulo/* 373214501Srpaulo Add a vlan interface with VLAN ID 'vid' and tagged interface 374214501Srpaulo 'if_name'. 375214501Srpaulo 376214501Srpaulo returns -1 on error 377214501Srpaulo returns 1 if the interface already exists 378214501Srpaulo returns 0 otherwise 379214501Srpaulo*/ 380214501Srpaulostatic int vlan_add(const char *if_name, int vid) 381214501Srpaulo{ 382214501Srpaulo int fd; 383214501Srpaulo struct vlan_ioctl_args if_request; 384214501Srpaulo 385214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", 386214501Srpaulo if_name, vid); 387214501Srpaulo ifconfig_up(if_name); 388214501Srpaulo 389214501Srpaulo if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 390214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 391214501Srpaulo if_name); 392214501Srpaulo return -1; 393214501Srpaulo } 394214501Srpaulo 395214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 396214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 397214501Srpaulo "failed: %s", __func__, strerror(errno)); 398214501Srpaulo return -1; 399214501Srpaulo } 400214501Srpaulo 401214501Srpaulo os_memset(&if_request, 0, sizeof(if_request)); 402214501Srpaulo 403214501Srpaulo /* Determine if a suitable vlan device already exists. */ 404214501Srpaulo 405214501Srpaulo os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d", 406214501Srpaulo vid); 407214501Srpaulo 408214501Srpaulo if_request.cmd = _GET_VLAN_VID_CMD; 409214501Srpaulo 410214501Srpaulo if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) { 411214501Srpaulo 412214501Srpaulo if (if_request.u.VID == vid) { 413214501Srpaulo if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD; 414214501Srpaulo 415214501Srpaulo if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && 416214501Srpaulo os_strncmp(if_request.u.device2, if_name, 417214501Srpaulo sizeof(if_request.u.device2)) == 0) { 418214501Srpaulo close(fd); 419214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_add: " 420214501Srpaulo "if_name %s exists already", 421214501Srpaulo if_request.device1); 422214501Srpaulo return 1; 423214501Srpaulo } 424214501Srpaulo } 425214501Srpaulo } 426214501Srpaulo 427214501Srpaulo /* A suitable vlan device does not already exist, add one. */ 428214501Srpaulo 429214501Srpaulo os_memset(&if_request, 0, sizeof(if_request)); 430214501Srpaulo os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 431214501Srpaulo if_request.u.VID = vid; 432214501Srpaulo if_request.cmd = ADD_VLAN_CMD; 433214501Srpaulo 434214501Srpaulo if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 435214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: " 436214501Srpaulo "%s", 437214501Srpaulo __func__, if_request.device1, strerror(errno)); 438214501Srpaulo close(fd); 439214501Srpaulo return -1; 440214501Srpaulo } 441214501Srpaulo 442214501Srpaulo close(fd); 443214501Srpaulo return 0; 444214501Srpaulo} 445214501Srpaulo 446214501Srpaulo 447214501Srpaulostatic int vlan_set_name_type(unsigned int name_type) 448214501Srpaulo{ 449214501Srpaulo int fd; 450214501Srpaulo struct vlan_ioctl_args if_request; 451214501Srpaulo 452214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", 453214501Srpaulo name_type); 454214501Srpaulo if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 455214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 456214501Srpaulo "failed: %s", __func__, strerror(errno)); 457214501Srpaulo return -1; 458214501Srpaulo } 459214501Srpaulo 460214501Srpaulo os_memset(&if_request, 0, sizeof(if_request)); 461214501Srpaulo 462214501Srpaulo if_request.u.name_type = name_type; 463214501Srpaulo if_request.cmd = SET_VLAN_NAME_TYPE_CMD; 464214501Srpaulo if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 465214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD " 466214501Srpaulo "name_type=%u failed: %s", 467214501Srpaulo __func__, name_type, strerror(errno)); 468214501Srpaulo close(fd); 469214501Srpaulo return -1; 470214501Srpaulo } 471214501Srpaulo 472214501Srpaulo close(fd); 473214501Srpaulo return 0; 474214501Srpaulo} 475214501Srpaulo 476214501Srpaulo 477214501Srpaulostatic void vlan_newlink(char *ifname, struct hostapd_data *hapd) 478214501Srpaulo{ 479214501Srpaulo char vlan_ifname[IFNAMSIZ]; 480214501Srpaulo char br_name[IFNAMSIZ]; 481214501Srpaulo struct hostapd_vlan *vlan = hapd->conf->vlan; 482214501Srpaulo char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; 483214501Srpaulo 484214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); 485214501Srpaulo 486214501Srpaulo while (vlan) { 487214501Srpaulo if (os_strcmp(ifname, vlan->ifname) == 0) { 488214501Srpaulo 489214501Srpaulo os_snprintf(br_name, sizeof(br_name), "brvlan%d", 490214501Srpaulo vlan->vlan_id); 491214501Srpaulo 492214501Srpaulo if (!br_addbr(br_name)) 493214501Srpaulo vlan->clean |= DVLAN_CLEAN_BR; 494214501Srpaulo 495214501Srpaulo ifconfig_up(br_name); 496214501Srpaulo 497214501Srpaulo if (tagged_interface) { 498214501Srpaulo 499214501Srpaulo if (!vlan_add(tagged_interface, vlan->vlan_id)) 500214501Srpaulo vlan->clean |= DVLAN_CLEAN_VLAN; 501214501Srpaulo 502214501Srpaulo os_snprintf(vlan_ifname, sizeof(vlan_ifname), 503214501Srpaulo "vlan%d", vlan->vlan_id); 504214501Srpaulo 505214501Srpaulo if (!br_addif(br_name, vlan_ifname)) 506214501Srpaulo vlan->clean |= DVLAN_CLEAN_VLAN_PORT; 507214501Srpaulo 508214501Srpaulo ifconfig_up(vlan_ifname); 509214501Srpaulo } 510214501Srpaulo 511214501Srpaulo if (!br_addif(br_name, ifname)) 512214501Srpaulo vlan->clean |= DVLAN_CLEAN_WLAN_PORT; 513214501Srpaulo 514214501Srpaulo ifconfig_up(ifname); 515214501Srpaulo 516214501Srpaulo break; 517214501Srpaulo } 518214501Srpaulo vlan = vlan->next; 519214501Srpaulo } 520214501Srpaulo} 521214501Srpaulo 522214501Srpaulo 523214501Srpaulostatic void vlan_dellink(char *ifname, struct hostapd_data *hapd) 524214501Srpaulo{ 525214501Srpaulo char vlan_ifname[IFNAMSIZ]; 526214501Srpaulo char br_name[IFNAMSIZ]; 527214501Srpaulo struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; 528214501Srpaulo char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; 529214501Srpaulo 530214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); 531214501Srpaulo 532214501Srpaulo first = prev = vlan; 533214501Srpaulo 534214501Srpaulo while (vlan) { 535214501Srpaulo if (os_strcmp(ifname, vlan->ifname) == 0) { 536214501Srpaulo os_snprintf(br_name, sizeof(br_name), "brvlan%d", 537214501Srpaulo vlan->vlan_id); 538214501Srpaulo 539214501Srpaulo if (vlan->clean & DVLAN_CLEAN_WLAN_PORT) 540214501Srpaulo br_delif(br_name, vlan->ifname); 541214501Srpaulo 542214501Srpaulo if (tagged_interface) { 543214501Srpaulo os_snprintf(vlan_ifname, sizeof(vlan_ifname), 544214501Srpaulo "vlan%d", vlan->vlan_id); 545214501Srpaulo if (vlan->clean & DVLAN_CLEAN_VLAN_PORT) 546214501Srpaulo br_delif(br_name, vlan_ifname); 547214501Srpaulo ifconfig_down(vlan_ifname); 548214501Srpaulo 549214501Srpaulo if (vlan->clean & DVLAN_CLEAN_VLAN) 550214501Srpaulo vlan_rem(vlan_ifname); 551214501Srpaulo } 552214501Srpaulo 553214501Srpaulo if ((vlan->clean & DVLAN_CLEAN_BR) && 554214501Srpaulo br_getnumports(br_name) == 0) { 555214501Srpaulo ifconfig_down(br_name); 556214501Srpaulo br_delbr(br_name); 557214501Srpaulo } 558214501Srpaulo 559214501Srpaulo if (vlan == first) { 560214501Srpaulo hapd->conf->vlan = vlan->next; 561214501Srpaulo } else { 562214501Srpaulo prev->next = vlan->next; 563214501Srpaulo } 564214501Srpaulo os_free(vlan); 565214501Srpaulo 566214501Srpaulo break; 567214501Srpaulo } 568214501Srpaulo prev = vlan; 569214501Srpaulo vlan = vlan->next; 570214501Srpaulo } 571214501Srpaulo} 572214501Srpaulo 573214501Srpaulo 574214501Srpaulostatic void 575214501Srpaulovlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, 576214501Srpaulo struct hostapd_data *hapd) 577214501Srpaulo{ 578214501Srpaulo struct ifinfomsg *ifi; 579214501Srpaulo int attrlen, nlmsg_len, rta_len; 580214501Srpaulo struct rtattr *attr; 581214501Srpaulo 582214501Srpaulo if (len < sizeof(*ifi)) 583214501Srpaulo return; 584214501Srpaulo 585214501Srpaulo ifi = NLMSG_DATA(h); 586214501Srpaulo 587214501Srpaulo nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); 588214501Srpaulo 589214501Srpaulo attrlen = h->nlmsg_len - nlmsg_len; 590214501Srpaulo if (attrlen < 0) 591214501Srpaulo return; 592214501Srpaulo 593214501Srpaulo attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); 594214501Srpaulo 595214501Srpaulo rta_len = RTA_ALIGN(sizeof(struct rtattr)); 596214501Srpaulo while (RTA_OK(attr, attrlen)) { 597214501Srpaulo char ifname[IFNAMSIZ + 1]; 598214501Srpaulo 599214501Srpaulo if (attr->rta_type == IFLA_IFNAME) { 600214501Srpaulo int n = attr->rta_len - rta_len; 601214501Srpaulo if (n < 0) 602214501Srpaulo break; 603214501Srpaulo 604214501Srpaulo os_memset(ifname, 0, sizeof(ifname)); 605214501Srpaulo 606214501Srpaulo if ((size_t) n > sizeof(ifname)) 607214501Srpaulo n = sizeof(ifname); 608214501Srpaulo os_memcpy(ifname, ((char *) attr) + rta_len, n); 609214501Srpaulo 610214501Srpaulo if (del) 611214501Srpaulo vlan_dellink(ifname, hapd); 612214501Srpaulo else 613214501Srpaulo vlan_newlink(ifname, hapd); 614214501Srpaulo } 615214501Srpaulo 616214501Srpaulo attr = RTA_NEXT(attr, attrlen); 617214501Srpaulo } 618214501Srpaulo} 619214501Srpaulo 620214501Srpaulo 621214501Srpaulostatic void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) 622214501Srpaulo{ 623214501Srpaulo char buf[8192]; 624214501Srpaulo int left; 625214501Srpaulo struct sockaddr_nl from; 626214501Srpaulo socklen_t fromlen; 627214501Srpaulo struct nlmsghdr *h; 628214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 629214501Srpaulo 630214501Srpaulo fromlen = sizeof(from); 631214501Srpaulo left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, 632214501Srpaulo (struct sockaddr *) &from, &fromlen); 633214501Srpaulo if (left < 0) { 634214501Srpaulo if (errno != EINTR && errno != EAGAIN) 635214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s", 636214501Srpaulo __func__, strerror(errno)); 637214501Srpaulo return; 638214501Srpaulo } 639214501Srpaulo 640214501Srpaulo h = (struct nlmsghdr *) buf; 641214501Srpaulo while (left >= (int) sizeof(*h)) { 642214501Srpaulo int len, plen; 643214501Srpaulo 644214501Srpaulo len = h->nlmsg_len; 645214501Srpaulo plen = len - sizeof(*h); 646214501Srpaulo if (len > left || plen < 0) { 647214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink " 648214501Srpaulo "message: len=%d left=%d plen=%d", 649214501Srpaulo len, left, plen); 650214501Srpaulo break; 651214501Srpaulo } 652214501Srpaulo 653214501Srpaulo switch (h->nlmsg_type) { 654214501Srpaulo case RTM_NEWLINK: 655214501Srpaulo vlan_read_ifnames(h, plen, 0, hapd); 656214501Srpaulo break; 657214501Srpaulo case RTM_DELLINK: 658214501Srpaulo vlan_read_ifnames(h, plen, 1, hapd); 659214501Srpaulo break; 660214501Srpaulo } 661214501Srpaulo 662214501Srpaulo len = NLMSG_ALIGN(len); 663214501Srpaulo left -= len; 664214501Srpaulo h = (struct nlmsghdr *) ((char *) h + len); 665214501Srpaulo } 666214501Srpaulo 667214501Srpaulo if (left > 0) { 668214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of " 669214501Srpaulo "netlink message", __func__, left); 670214501Srpaulo } 671214501Srpaulo} 672214501Srpaulo 673214501Srpaulo 674214501Srpaulostatic struct full_dynamic_vlan * 675214501Srpaulofull_dynamic_vlan_init(struct hostapd_data *hapd) 676214501Srpaulo{ 677214501Srpaulo struct sockaddr_nl local; 678214501Srpaulo struct full_dynamic_vlan *priv; 679214501Srpaulo 680214501Srpaulo priv = os_zalloc(sizeof(*priv)); 681214501Srpaulo if (priv == NULL) 682214501Srpaulo return NULL; 683214501Srpaulo 684214501Srpaulo vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD); 685214501Srpaulo 686214501Srpaulo priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 687214501Srpaulo if (priv->s < 0) { 688214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW," 689214501Srpaulo "NETLINK_ROUTE) failed: %s", 690214501Srpaulo __func__, strerror(errno)); 691214501Srpaulo os_free(priv); 692214501Srpaulo return NULL; 693214501Srpaulo } 694214501Srpaulo 695214501Srpaulo os_memset(&local, 0, sizeof(local)); 696214501Srpaulo local.nl_family = AF_NETLINK; 697214501Srpaulo local.nl_groups = RTMGRP_LINK; 698214501Srpaulo if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) { 699214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s", 700214501Srpaulo __func__, strerror(errno)); 701214501Srpaulo close(priv->s); 702214501Srpaulo os_free(priv); 703214501Srpaulo return NULL; 704214501Srpaulo } 705214501Srpaulo 706214501Srpaulo if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL)) 707214501Srpaulo { 708214501Srpaulo close(priv->s); 709214501Srpaulo os_free(priv); 710214501Srpaulo return NULL; 711214501Srpaulo } 712214501Srpaulo 713214501Srpaulo return priv; 714214501Srpaulo} 715214501Srpaulo 716214501Srpaulo 717214501Srpaulostatic void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv) 718214501Srpaulo{ 719214501Srpaulo if (priv == NULL) 720214501Srpaulo return; 721214501Srpaulo eloop_unregister_read_sock(priv->s); 722214501Srpaulo close(priv->s); 723214501Srpaulo os_free(priv); 724214501Srpaulo} 725214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 726214501Srpaulo 727214501Srpaulo 728214501Srpauloint vlan_setup_encryption_dyn(struct hostapd_data *hapd, 729214501Srpaulo struct hostapd_ssid *mssid, const char *dyn_vlan) 730214501Srpaulo{ 731214501Srpaulo int i; 732214501Srpaulo 733214501Srpaulo if (dyn_vlan == NULL) 734214501Srpaulo return 0; 735214501Srpaulo 736214501Srpaulo /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own 737214501Srpaulo * functions for setting up dynamic broadcast keys. */ 738214501Srpaulo for (i = 0; i < 4; i++) { 739214501Srpaulo if (mssid->wep.key[i] && 740214501Srpaulo hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, 741214501Srpaulo i == mssid->wep.idx, NULL, 0, 742214501Srpaulo mssid->wep.key[i], mssid->wep.len[i])) { 743214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " 744214501Srpaulo "encryption for dynamic VLAN"); 745214501Srpaulo return -1; 746214501Srpaulo } 747214501Srpaulo } 748214501Srpaulo 749214501Srpaulo return 0; 750214501Srpaulo} 751214501Srpaulo 752214501Srpaulo 753214501Srpaulostatic int vlan_dynamic_add(struct hostapd_data *hapd, 754214501Srpaulo struct hostapd_vlan *vlan) 755214501Srpaulo{ 756214501Srpaulo while (vlan) { 757214501Srpaulo if (vlan->vlan_id != VLAN_ID_WILDCARD) { 758214501Srpaulo if (hapd->drv.vlan_if_add(hapd, vlan->ifname)) { 759214501Srpaulo if (errno != EEXIST) { 760214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: Could " 761214501Srpaulo "not add VLAN %s: %s", 762214501Srpaulo vlan->ifname, 763214501Srpaulo strerror(errno)); 764214501Srpaulo return -1; 765214501Srpaulo } 766214501Srpaulo } 767214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 768214501Srpaulo ifconfig_up(vlan->ifname); 769214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 770214501Srpaulo } 771214501Srpaulo 772214501Srpaulo vlan = vlan->next; 773214501Srpaulo } 774214501Srpaulo 775214501Srpaulo return 0; 776214501Srpaulo} 777214501Srpaulo 778214501Srpaulo 779214501Srpaulostatic void vlan_dynamic_remove(struct hostapd_data *hapd, 780214501Srpaulo struct hostapd_vlan *vlan) 781214501Srpaulo{ 782214501Srpaulo struct hostapd_vlan *next; 783214501Srpaulo 784214501Srpaulo while (vlan) { 785214501Srpaulo next = vlan->next; 786214501Srpaulo 787214501Srpaulo if (vlan->vlan_id != VLAN_ID_WILDCARD && 788214501Srpaulo hapd->drv.vlan_if_remove(hapd, vlan->ifname)) { 789214501Srpaulo wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " 790214501Srpaulo "iface: %s: %s", 791214501Srpaulo vlan->ifname, strerror(errno)); 792214501Srpaulo } 793214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 794214501Srpaulo if (vlan->clean) 795214501Srpaulo vlan_dellink(vlan->ifname, hapd); 796214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 797214501Srpaulo 798214501Srpaulo vlan = next; 799214501Srpaulo } 800214501Srpaulo} 801214501Srpaulo 802214501Srpaulo 803214501Srpauloint vlan_init(struct hostapd_data *hapd) 804214501Srpaulo{ 805214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 806214501Srpaulo hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); 807214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 808214501Srpaulo 809214501Srpaulo if (vlan_dynamic_add(hapd, hapd->conf->vlan)) 810214501Srpaulo return -1; 811214501Srpaulo 812214501Srpaulo return 0; 813214501Srpaulo} 814214501Srpaulo 815214501Srpaulo 816214501Srpaulovoid vlan_deinit(struct hostapd_data *hapd) 817214501Srpaulo{ 818214501Srpaulo vlan_dynamic_remove(hapd, hapd->conf->vlan); 819214501Srpaulo 820214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 821214501Srpaulo full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); 822214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 823214501Srpaulo} 824214501Srpaulo 825214501Srpaulo 826214501Srpaulostruct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, 827214501Srpaulo struct hostapd_vlan *vlan, 828214501Srpaulo int vlan_id) 829214501Srpaulo{ 830214501Srpaulo struct hostapd_vlan *n; 831214501Srpaulo char *ifname, *pos; 832214501Srpaulo 833214501Srpaulo if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID || 834214501Srpaulo vlan->vlan_id != VLAN_ID_WILDCARD) 835214501Srpaulo return NULL; 836214501Srpaulo 837214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", 838214501Srpaulo __func__, vlan_id, vlan->ifname); 839214501Srpaulo ifname = os_strdup(vlan->ifname); 840214501Srpaulo if (ifname == NULL) 841214501Srpaulo return NULL; 842214501Srpaulo pos = os_strchr(ifname, '#'); 843214501Srpaulo if (pos == NULL) { 844214501Srpaulo os_free(ifname); 845214501Srpaulo return NULL; 846214501Srpaulo } 847214501Srpaulo *pos++ = '\0'; 848214501Srpaulo 849214501Srpaulo n = os_zalloc(sizeof(*n)); 850214501Srpaulo if (n == NULL) { 851214501Srpaulo os_free(ifname); 852214501Srpaulo return NULL; 853214501Srpaulo } 854214501Srpaulo 855214501Srpaulo n->vlan_id = vlan_id; 856214501Srpaulo n->dynamic_vlan = 1; 857214501Srpaulo 858214501Srpaulo os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, 859214501Srpaulo pos); 860214501Srpaulo os_free(ifname); 861214501Srpaulo 862214501Srpaulo if (hapd->drv.vlan_if_add(hapd, n->ifname)) { 863214501Srpaulo os_free(n); 864214501Srpaulo return NULL; 865214501Srpaulo } 866214501Srpaulo 867214501Srpaulo n->next = hapd->conf->vlan; 868214501Srpaulo hapd->conf->vlan = n; 869214501Srpaulo 870214501Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 871214501Srpaulo ifconfig_up(n->ifname); 872214501Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 873214501Srpaulo 874214501Srpaulo return n; 875214501Srpaulo} 876214501Srpaulo 877214501Srpaulo 878214501Srpauloint vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) 879214501Srpaulo{ 880214501Srpaulo struct hostapd_vlan *vlan; 881214501Srpaulo 882214501Srpaulo if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) 883214501Srpaulo return 1; 884214501Srpaulo 885214501Srpaulo wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); 886214501Srpaulo 887214501Srpaulo vlan = hapd->conf->vlan; 888214501Srpaulo while (vlan) { 889214501Srpaulo if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { 890214501Srpaulo vlan->dynamic_vlan--; 891214501Srpaulo break; 892214501Srpaulo } 893214501Srpaulo vlan = vlan->next; 894214501Srpaulo } 895214501Srpaulo 896214501Srpaulo if (vlan == NULL) 897214501Srpaulo return 1; 898214501Srpaulo 899214501Srpaulo if (vlan->dynamic_vlan == 0) 900214501Srpaulo hapd->drv.vlan_if_remove(hapd, vlan->ifname); 901214501Srpaulo 902214501Srpaulo return 0; 903214501Srpaulo} 904