vlan_init.c revision 252726
1219019Sgabor/* 2219019Sgabor * hostapd / VLAN initialization 3219019Sgabor * Copyright 2003, Instant802 Networks, Inc. 4219019Sgabor * Copyright 2005-2006, Devicescape Software, Inc. 5219019Sgabor * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 6219019Sgabor * 7219019Sgabor * This program is free software; you can redistribute it and/or modify 8219019Sgabor * it under the terms of the GNU General Public License version 2 as 9219019Sgabor * published by the Free Software Foundation. 10219019Sgabor * 11219019Sgabor * Alternatively, this software may be distributed under the terms of BSD 12219019Sgabor * license. 13219019Sgabor * 14219019Sgabor * See README and COPYING for more details. 15219019Sgabor */ 16219019Sgabor 17219019Sgabor#include "utils/includes.h" 18219019Sgabor 19219019Sgabor#include "utils/common.h" 20219019Sgabor#include "hostapd.h" 21219019Sgabor#include "ap_config.h" 22219019Sgabor#include "ap_drv_ops.h" 23219019Sgabor#include "vlan_init.h" 24219019Sgabor#include "vlan_util.h" 25219019Sgabor 26219019Sgabor 27219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 28219019Sgabor 29219019Sgabor#include <net/if.h> 30219019Sgabor#include <sys/ioctl.h> 31219019Sgabor#include <linux/sockios.h> 32219019Sgabor#include <linux/if_vlan.h> 33219019Sgabor#include <linux/if_bridge.h> 34219019Sgabor 35219019Sgabor#include "drivers/priv_netlink.h" 36219019Sgabor#include "utils/eloop.h" 37219019Sgabor 38219019Sgabor 39219019Sgaborstruct full_dynamic_vlan { 40219019Sgabor int s; /* socket on which to listen for new/removed interfaces. */ 41219019Sgabor}; 42219019Sgabor 43219019Sgabor 44219019Sgaborstatic int ifconfig_helper(const char *if_name, int up) 45219019Sgabor{ 46219019Sgabor int fd; 47219019Sgabor struct ifreq ifr; 48219019Sgabor 49219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 50219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 51219019Sgabor "failed: %s", __func__, strerror(errno)); 52219019Sgabor return -1; 53219019Sgabor } 54219019Sgabor 55219019Sgabor os_memset(&ifr, 0, sizeof(ifr)); 56219019Sgabor os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); 57219019Sgabor 58219019Sgabor if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { 59219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed " 60219019Sgabor "for interface %s: %s", 61219019Sgabor __func__, if_name, strerror(errno)); 62219019Sgabor close(fd); 63219019Sgabor return -1; 64219019Sgabor } 65219019Sgabor 66219019Sgabor if (up) 67219019Sgabor ifr.ifr_flags |= IFF_UP; 68219019Sgabor else 69219019Sgabor ifr.ifr_flags &= ~IFF_UP; 70219019Sgabor 71219019Sgabor if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) { 72219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed " 73219019Sgabor "for interface %s (up=%d): %s", 74219019Sgabor __func__, if_name, up, strerror(errno)); 75219019Sgabor close(fd); 76219019Sgabor return -1; 77219019Sgabor } 78219019Sgabor 79219019Sgabor close(fd); 80219019Sgabor return 0; 81219019Sgabor} 82219019Sgabor 83219019Sgabor 84219019Sgaborstatic int ifconfig_up(const char *if_name) 85219019Sgabor{ 86219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name); 87219019Sgabor return ifconfig_helper(if_name, 1); 88219019Sgabor} 89219019Sgabor 90219019Sgabor 91219019Sgaborstatic int ifconfig_down(const char *if_name) 92219019Sgabor{ 93219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name); 94219019Sgabor return ifconfig_helper(if_name, 0); 95219019Sgabor} 96219019Sgabor 97219019Sgabor 98219019Sgabor/* 99219019Sgabor * These are only available in recent linux headers (without the leading 100219019Sgabor * underscore). 101219019Sgabor */ 102219019Sgabor#define _GET_VLAN_REALDEV_NAME_CMD 8 103219019Sgabor#define _GET_VLAN_VID_CMD 9 104219019Sgabor 105219019Sgabor/* This value should be 256 ONLY. If it is something else, then hostapd 106219019Sgabor * might crash!, as this value has been hard-coded in 2.4.x kernel 107219019Sgabor * bridging code. 108219019Sgabor */ 109219019Sgabor#define MAX_BR_PORTS 256 110219019Sgabor 111219019Sgaborstatic int br_delif(const char *br_name, const char *if_name) 112219019Sgabor{ 113219019Sgabor int fd; 114219019Sgabor struct ifreq ifr; 115219019Sgabor unsigned long args[2]; 116219019Sgabor int if_index; 117219019Sgabor 118219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name); 119219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 120219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 121219019Sgabor "failed: %s", __func__, strerror(errno)); 122219019Sgabor return -1; 123219019Sgabor } 124219019Sgabor 125219019Sgabor if_index = if_nametoindex(if_name); 126219019Sgabor 127219019Sgabor if (if_index == 0) { 128219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " 129219019Sgabor "interface index for '%s'", 130219019Sgabor __func__, if_name); 131219019Sgabor close(fd); 132219019Sgabor return -1; 133219019Sgabor } 134219019Sgabor 135219019Sgabor args[0] = BRCTL_DEL_IF; 136219019Sgabor args[1] = if_index; 137219019Sgabor 138219019Sgabor os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 139219019Sgabor ifr.ifr_data = (__caddr_t) args; 140219019Sgabor 141219019Sgabor if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) { 142219019Sgabor /* No error if interface already removed. */ 143219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," 144219019Sgabor "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: " 145219019Sgabor "%s", __func__, br_name, if_name, strerror(errno)); 146219019Sgabor close(fd); 147219019Sgabor return -1; 148219019Sgabor } 149219019Sgabor 150219019Sgabor close(fd); 151219019Sgabor return 0; 152219019Sgabor} 153219019Sgabor 154219019Sgabor 155219019Sgabor/* 156219019Sgabor Add interface 'if_name' to the bridge 'br_name' 157219019Sgabor 158219019Sgabor returns -1 on error 159219019Sgabor returns 1 if the interface is already part of the bridge 160219019Sgabor returns 0 otherwise 161219019Sgabor*/ 162219019Sgaborstatic int br_addif(const char *br_name, const char *if_name) 163219019Sgabor{ 164219019Sgabor int fd; 165219019Sgabor struct ifreq ifr; 166219019Sgabor unsigned long args[2]; 167219019Sgabor int if_index; 168219019Sgabor 169219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name); 170219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 171219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 172219019Sgabor "failed: %s", __func__, strerror(errno)); 173219019Sgabor return -1; 174219019Sgabor } 175219019Sgabor 176219019Sgabor if_index = if_nametoindex(if_name); 177219019Sgabor 178219019Sgabor if (if_index == 0) { 179219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " 180219019Sgabor "interface index for '%s'", 181219019Sgabor __func__, if_name); 182219019Sgabor close(fd); 183219019Sgabor return -1; 184219019Sgabor } 185219019Sgabor 186219019Sgabor args[0] = BRCTL_ADD_IF; 187219019Sgabor args[1] = if_index; 188219019Sgabor 189219019Sgabor os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 190219019Sgabor ifr.ifr_data = (__caddr_t) args; 191219019Sgabor 192219019Sgabor if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 193219019Sgabor if (errno == EBUSY) { 194219019Sgabor /* The interface is already added. */ 195219019Sgabor close(fd); 196219019Sgabor return 1; 197219019Sgabor } 198219019Sgabor 199219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," 200219019Sgabor "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: " 201219019Sgabor "%s", __func__, br_name, if_name, strerror(errno)); 202219019Sgabor close(fd); 203219019Sgabor return -1; 204219019Sgabor } 205219019Sgabor 206219019Sgabor close(fd); 207219019Sgabor return 0; 208219019Sgabor} 209219019Sgabor 210219019Sgabor 211219019Sgaborstatic int br_delbr(const char *br_name) 212219019Sgabor{ 213219019Sgabor int fd; 214219019Sgabor unsigned long arg[2]; 215219019Sgabor 216219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name); 217219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 218219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 219219019Sgabor "failed: %s", __func__, strerror(errno)); 220219019Sgabor return -1; 221219019Sgabor } 222219019Sgabor 223219019Sgabor arg[0] = BRCTL_DEL_BRIDGE; 224219019Sgabor arg[1] = (unsigned long) br_name; 225219019Sgabor 226219019Sgabor if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) { 227219019Sgabor /* No error if bridge already removed. */ 228219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for " 229219019Sgabor "%s: %s", __func__, br_name, strerror(errno)); 230219019Sgabor close(fd); 231219019Sgabor return -1; 232219019Sgabor } 233219019Sgabor 234219019Sgabor close(fd); 235219019Sgabor return 0; 236219019Sgabor} 237219019Sgabor 238219019Sgabor 239219019Sgabor/* 240219019Sgabor Add a bridge with the name 'br_name'. 241219019Sgabor 242219019Sgabor returns -1 on error 243219019Sgabor returns 1 if the bridge already exists 244219019Sgabor returns 0 otherwise 245219019Sgabor*/ 246219019Sgaborstatic int br_addbr(const char *br_name) 247219019Sgabor{ 248219019Sgabor int fd; 249219019Sgabor unsigned long arg[4]; 250219019Sgabor struct ifreq ifr; 251219019Sgabor 252219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name); 253219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 254219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 255219019Sgabor "failed: %s", __func__, strerror(errno)); 256219019Sgabor return -1; 257219019Sgabor } 258219019Sgabor 259219019Sgabor arg[0] = BRCTL_ADD_BRIDGE; 260219019Sgabor arg[1] = (unsigned long) br_name; 261219019Sgabor 262219019Sgabor if (ioctl(fd, SIOCGIFBR, arg) < 0) { 263219019Sgabor if (errno == EEXIST) { 264219019Sgabor /* The bridge is already added. */ 265219019Sgabor close(fd); 266219019Sgabor return 1; 267219019Sgabor } else { 268219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE " 269219019Sgabor "failed for %s: %s", 270219019Sgabor __func__, br_name, strerror(errno)); 271219019Sgabor close(fd); 272219019Sgabor return -1; 273219019Sgabor } 274219019Sgabor } 275219019Sgabor 276219019Sgabor /* Decrease forwarding delay to avoid EAPOL timeouts. */ 277219019Sgabor os_memset(&ifr, 0, sizeof(ifr)); 278219019Sgabor os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ); 279219019Sgabor arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; 280219019Sgabor arg[1] = 1; 281219019Sgabor arg[2] = 0; 282219019Sgabor arg[3] = 0; 283219019Sgabor ifr.ifr_data = (char *) &arg; 284219019Sgabor if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 285219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: " 286219019Sgabor "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for " 287219019Sgabor "%s: %s", __func__, br_name, strerror(errno)); 288219019Sgabor /* Continue anyway */ 289219019Sgabor } 290219019Sgabor 291219019Sgabor close(fd); 292219019Sgabor return 0; 293219019Sgabor} 294219019Sgabor 295219019Sgabor 296219019Sgaborstatic int br_getnumports(const char *br_name) 297219019Sgabor{ 298219019Sgabor int fd; 299219019Sgabor int i; 300219019Sgabor int port_cnt = 0; 301219019Sgabor unsigned long arg[4]; 302219019Sgabor int ifindices[MAX_BR_PORTS]; 303219019Sgabor struct ifreq ifr; 304219019Sgabor 305219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 306219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 307219019Sgabor "failed: %s", __func__, strerror(errno)); 308219019Sgabor return -1; 309219019Sgabor } 310219019Sgabor 311219019Sgabor arg[0] = BRCTL_GET_PORT_LIST; 312219019Sgabor arg[1] = (unsigned long) ifindices; 313219019Sgabor arg[2] = MAX_BR_PORTS; 314219019Sgabor arg[3] = 0; 315219019Sgabor 316219019Sgabor os_memset(ifindices, 0, sizeof(ifindices)); 317219019Sgabor os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); 318219019Sgabor ifr.ifr_data = (__caddr_t) arg; 319219019Sgabor 320219019Sgabor if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { 321219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST " 322219019Sgabor "failed for %s: %s", 323219019Sgabor __func__, br_name, strerror(errno)); 324219019Sgabor close(fd); 325219019Sgabor return -1; 326219019Sgabor } 327219019Sgabor 328219019Sgabor for (i = 1; i < MAX_BR_PORTS; i++) { 329219019Sgabor if (ifindices[i] > 0) { 330219019Sgabor port_cnt++; 331219019Sgabor } 332219019Sgabor } 333219019Sgabor 334219019Sgabor close(fd); 335219019Sgabor return port_cnt; 336219019Sgabor} 337219019Sgabor 338219019Sgabor 339219019Sgabor#ifndef CONFIG_VLAN_NETLINK 340219019Sgabor 341219019Sgaborint vlan_rem(const char *if_name) 342219019Sgabor{ 343219019Sgabor int fd; 344219019Sgabor struct vlan_ioctl_args if_request; 345219019Sgabor 346219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); 347219019Sgabor if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 348219019Sgabor wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 349219019Sgabor if_name); 350219019Sgabor return -1; 351219019Sgabor } 352219019Sgabor 353219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 354219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 355219019Sgabor "failed: %s", __func__, strerror(errno)); 356219019Sgabor return -1; 357219019Sgabor } 358219019Sgabor 359219019Sgabor os_memset(&if_request, 0, sizeof(if_request)); 360219019Sgabor 361219019Sgabor os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 362219019Sgabor if_request.cmd = DEL_VLAN_CMD; 363219019Sgabor 364219019Sgabor if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 365219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " 366219019Sgabor "%s", __func__, if_name, strerror(errno)); 367219019Sgabor close(fd); 368219019Sgabor return -1; 369219019Sgabor } 370219019Sgabor 371219019Sgabor close(fd); 372219019Sgabor return 0; 373219019Sgabor} 374219019Sgabor 375219019Sgabor 376219019Sgabor/* 377219019Sgabor Add a vlan interface with VLAN ID 'vid' and tagged interface 378219019Sgabor 'if_name'. 379219019Sgabor 380219019Sgabor returns -1 on error 381219019Sgabor returns 1 if the interface already exists 382219019Sgabor returns 0 otherwise 383219019Sgabor*/ 384219019Sgaborint vlan_add(const char *if_name, int vid, const char *vlan_if_name) 385219019Sgabor{ 386219019Sgabor int fd; 387219019Sgabor struct vlan_ioctl_args if_request; 388219019Sgabor 389219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", 390219019Sgabor if_name, vid); 391219019Sgabor ifconfig_up(if_name); 392219019Sgabor 393219019Sgabor if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 394219019Sgabor wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 395219019Sgabor if_name); 396219019Sgabor return -1; 397219019Sgabor } 398219019Sgabor 399219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 400219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 401219019Sgabor "failed: %s", __func__, strerror(errno)); 402219019Sgabor return -1; 403219019Sgabor } 404219019Sgabor 405219019Sgabor os_memset(&if_request, 0, sizeof(if_request)); 406219019Sgabor 407219019Sgabor /* Determine if a suitable vlan device already exists. */ 408219019Sgabor 409219019Sgabor os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d", 410219019Sgabor vid); 411219019Sgabor 412219019Sgabor if_request.cmd = _GET_VLAN_VID_CMD; 413219019Sgabor 414219019Sgabor if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) { 415219019Sgabor 416219019Sgabor if (if_request.u.VID == vid) { 417219019Sgabor if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD; 418219019Sgabor 419219019Sgabor if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && 420219019Sgabor os_strncmp(if_request.u.device2, if_name, 421219019Sgabor sizeof(if_request.u.device2)) == 0) { 422219019Sgabor close(fd); 423219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_add: " 424219019Sgabor "if_name %s exists already", 425219019Sgabor if_request.device1); 426219019Sgabor return 1; 427219019Sgabor } 428219019Sgabor } 429219019Sgabor } 430219019Sgabor 431219019Sgabor /* A suitable vlan device does not already exist, add one. */ 432219019Sgabor 433219019Sgabor os_memset(&if_request, 0, sizeof(if_request)); 434219019Sgabor os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 435219019Sgabor if_request.u.VID = vid; 436219019Sgabor if_request.cmd = ADD_VLAN_CMD; 437219019Sgabor 438219019Sgabor if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 439219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: " 440219019Sgabor "%s", 441219019Sgabor __func__, if_request.device1, strerror(errno)); 442219019Sgabor close(fd); 443219019Sgabor return -1; 444219019Sgabor } 445219019Sgabor 446219019Sgabor close(fd); 447219019Sgabor return 0; 448219019Sgabor} 449219019Sgabor 450219019Sgabor 451219019Sgaborstatic int vlan_set_name_type(unsigned int name_type) 452219019Sgabor{ 453219019Sgabor int fd; 454219019Sgabor struct vlan_ioctl_args if_request; 455219019Sgabor 456219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", 457219019Sgabor name_type); 458219019Sgabor if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 459219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 460219019Sgabor "failed: %s", __func__, strerror(errno)); 461219019Sgabor return -1; 462219019Sgabor } 463219019Sgabor 464219019Sgabor os_memset(&if_request, 0, sizeof(if_request)); 465219019Sgabor 466219019Sgabor if_request.u.name_type = name_type; 467219019Sgabor if_request.cmd = SET_VLAN_NAME_TYPE_CMD; 468219019Sgabor if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 469219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD " 470219019Sgabor "name_type=%u failed: %s", 471219019Sgabor __func__, name_type, strerror(errno)); 472219019Sgabor close(fd); 473219019Sgabor return -1; 474219019Sgabor } 475219019Sgabor 476219019Sgabor close(fd); 477219019Sgabor return 0; 478219019Sgabor} 479219019Sgabor 480219019Sgabor#endif /* CONFIG_VLAN_NETLINK */ 481219019Sgabor 482219019Sgabor 483219019Sgaborstatic void vlan_newlink(char *ifname, struct hostapd_data *hapd) 484219019Sgabor{ 485219019Sgabor char vlan_ifname[IFNAMSIZ]; 486219019Sgabor char br_name[IFNAMSIZ]; 487219019Sgabor struct hostapd_vlan *vlan = hapd->conf->vlan; 488219019Sgabor char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; 489219019Sgabor int vlan_naming = hapd->conf->ssid.vlan_naming; 490219019Sgabor 491219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); 492219019Sgabor 493219019Sgabor while (vlan) { 494219019Sgabor if (os_strcmp(ifname, vlan->ifname) == 0) { 495219019Sgabor 496219019Sgabor os_snprintf(br_name, sizeof(br_name), "brvlan%d", 497219019Sgabor vlan->vlan_id); 498219019Sgabor 499219019Sgabor if (!br_addbr(br_name)) 500219019Sgabor vlan->clean |= DVLAN_CLEAN_BR; 501219019Sgabor 502219019Sgabor ifconfig_up(br_name); 503219019Sgabor 504219019Sgabor if (tagged_interface) { 505219019Sgabor if (vlan_naming == 506219019Sgabor DYNAMIC_VLAN_NAMING_WITH_DEVICE) 507219019Sgabor os_snprintf(vlan_ifname, 508219019Sgabor sizeof(vlan_ifname), 509219019Sgabor "%s.%d", tagged_interface, 510219019Sgabor vlan->vlan_id); 511219019Sgabor else 512219019Sgabor os_snprintf(vlan_ifname, 513219019Sgabor sizeof(vlan_ifname), 514219019Sgabor "vlan%d", vlan->vlan_id); 515219019Sgabor 516219019Sgabor ifconfig_up(tagged_interface); 517219019Sgabor if (!vlan_add(tagged_interface, vlan->vlan_id, 518219019Sgabor vlan_ifname)) 519219019Sgabor vlan->clean |= DVLAN_CLEAN_VLAN; 520219019Sgabor 521219019Sgabor if (!br_addif(br_name, vlan_ifname)) 522219019Sgabor vlan->clean |= DVLAN_CLEAN_VLAN_PORT; 523219019Sgabor 524219019Sgabor ifconfig_up(vlan_ifname); 525219019Sgabor } 526219019Sgabor 527219019Sgabor if (!br_addif(br_name, ifname)) 528219019Sgabor vlan->clean |= DVLAN_CLEAN_WLAN_PORT; 529219019Sgabor 530219019Sgabor ifconfig_up(ifname); 531219019Sgabor 532219019Sgabor break; 533219019Sgabor } 534219019Sgabor vlan = vlan->next; 535219019Sgabor } 536219019Sgabor} 537219019Sgabor 538219019Sgabor 539219019Sgaborstatic void vlan_dellink(char *ifname, struct hostapd_data *hapd) 540219019Sgabor{ 541219019Sgabor char vlan_ifname[IFNAMSIZ]; 542219019Sgabor char br_name[IFNAMSIZ]; 543219019Sgabor struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; 544219019Sgabor char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; 545219019Sgabor int vlan_naming = hapd->conf->ssid.vlan_naming; 546219019Sgabor 547219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); 548219019Sgabor 549219019Sgabor first = prev = vlan; 550219019Sgabor 551219019Sgabor while (vlan) { 552219019Sgabor if (os_strcmp(ifname, vlan->ifname) == 0) { 553219019Sgabor os_snprintf(br_name, sizeof(br_name), "brvlan%d", 554219019Sgabor vlan->vlan_id); 555219019Sgabor 556219019Sgabor if (vlan->clean & DVLAN_CLEAN_WLAN_PORT) 557219019Sgabor br_delif(br_name, vlan->ifname); 558219019Sgabor 559219019Sgabor if (tagged_interface) { 560219019Sgabor if (vlan_naming == 561219019Sgabor DYNAMIC_VLAN_NAMING_WITH_DEVICE) 562219019Sgabor os_snprintf(vlan_ifname, 563219019Sgabor sizeof(vlan_ifname), 564219019Sgabor "%s.%d", tagged_interface, 565219019Sgabor vlan->vlan_id); 566219019Sgabor else 567219019Sgabor os_snprintf(vlan_ifname, 568219019Sgabor sizeof(vlan_ifname), 569219019Sgabor "vlan%d", vlan->vlan_id); 570219019Sgabor if (vlan->clean & DVLAN_CLEAN_VLAN_PORT) 571219019Sgabor br_delif(br_name, vlan_ifname); 572219019Sgabor ifconfig_down(vlan_ifname); 573219019Sgabor 574219019Sgabor if (vlan->clean & DVLAN_CLEAN_VLAN) 575219019Sgabor vlan_rem(vlan_ifname); 576219019Sgabor } 577219019Sgabor 578219019Sgabor if ((vlan->clean & DVLAN_CLEAN_BR) && 579219019Sgabor br_getnumports(br_name) == 0) { 580219019Sgabor ifconfig_down(br_name); 581219019Sgabor br_delbr(br_name); 582219019Sgabor } 583219019Sgabor 584219019Sgabor if (vlan == first) { 585219019Sgabor hapd->conf->vlan = vlan->next; 586219019Sgabor } else { 587219019Sgabor prev->next = vlan->next; 588219019Sgabor } 589219019Sgabor os_free(vlan); 590219019Sgabor 591219019Sgabor break; 592219019Sgabor } 593219019Sgabor prev = vlan; 594219019Sgabor vlan = vlan->next; 595219019Sgabor } 596219019Sgabor} 597219019Sgabor 598219019Sgabor 599219019Sgaborstatic void 600219019Sgaborvlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, 601219019Sgabor struct hostapd_data *hapd) 602219019Sgabor{ 603219019Sgabor struct ifinfomsg *ifi; 604219019Sgabor int attrlen, nlmsg_len, rta_len; 605219019Sgabor struct rtattr *attr; 606219019Sgabor 607219019Sgabor if (len < sizeof(*ifi)) 608219019Sgabor return; 609219019Sgabor 610219019Sgabor ifi = NLMSG_DATA(h); 611219019Sgabor 612219019Sgabor nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); 613219019Sgabor 614219019Sgabor attrlen = h->nlmsg_len - nlmsg_len; 615219019Sgabor if (attrlen < 0) 616219019Sgabor return; 617219019Sgabor 618219019Sgabor attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); 619219019Sgabor 620219019Sgabor rta_len = RTA_ALIGN(sizeof(struct rtattr)); 621219019Sgabor while (RTA_OK(attr, attrlen)) { 622219019Sgabor char ifname[IFNAMSIZ + 1]; 623219019Sgabor 624219019Sgabor if (attr->rta_type == IFLA_IFNAME) { 625219019Sgabor int n = attr->rta_len - rta_len; 626219019Sgabor if (n < 0) 627219019Sgabor break; 628219019Sgabor 629219019Sgabor os_memset(ifname, 0, sizeof(ifname)); 630219019Sgabor 631219019Sgabor if ((size_t) n > sizeof(ifname)) 632219019Sgabor n = sizeof(ifname); 633219019Sgabor os_memcpy(ifname, ((char *) attr) + rta_len, n); 634219019Sgabor 635219019Sgabor if (del) 636219019Sgabor vlan_dellink(ifname, hapd); 637219019Sgabor else 638219019Sgabor vlan_newlink(ifname, hapd); 639219019Sgabor } 640219019Sgabor 641219019Sgabor attr = RTA_NEXT(attr, attrlen); 642219019Sgabor } 643219019Sgabor} 644219019Sgabor 645219019Sgabor 646219019Sgaborstatic void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) 647219019Sgabor{ 648219019Sgabor char buf[8192]; 649219019Sgabor int left; 650219019Sgabor struct sockaddr_nl from; 651219019Sgabor socklen_t fromlen; 652219019Sgabor struct nlmsghdr *h; 653219019Sgabor struct hostapd_data *hapd = eloop_ctx; 654219019Sgabor 655219019Sgabor fromlen = sizeof(from); 656219019Sgabor left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, 657219019Sgabor (struct sockaddr *) &from, &fromlen); 658219019Sgabor if (left < 0) { 659219019Sgabor if (errno != EINTR && errno != EAGAIN) 660219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s", 661219019Sgabor __func__, strerror(errno)); 662219019Sgabor return; 663219019Sgabor } 664219019Sgabor 665219019Sgabor h = (struct nlmsghdr *) buf; 666219019Sgabor while (left >= (int) sizeof(*h)) { 667219019Sgabor int len, plen; 668219019Sgabor 669219019Sgabor len = h->nlmsg_len; 670219019Sgabor plen = len - sizeof(*h); 671219019Sgabor if (len > left || plen < 0) { 672219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink " 673219019Sgabor "message: len=%d left=%d plen=%d", 674219019Sgabor len, left, plen); 675219019Sgabor break; 676219019Sgabor } 677219019Sgabor 678219019Sgabor switch (h->nlmsg_type) { 679219019Sgabor case RTM_NEWLINK: 680219019Sgabor vlan_read_ifnames(h, plen, 0, hapd); 681219019Sgabor break; 682219019Sgabor case RTM_DELLINK: 683219019Sgabor vlan_read_ifnames(h, plen, 1, hapd); 684219019Sgabor break; 685219019Sgabor } 686219019Sgabor 687219019Sgabor len = NLMSG_ALIGN(len); 688219019Sgabor left -= len; 689219019Sgabor h = (struct nlmsghdr *) ((char *) h + len); 690219019Sgabor } 691219019Sgabor 692219019Sgabor if (left > 0) { 693219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of " 694219019Sgabor "netlink message", __func__, left); 695219019Sgabor } 696219019Sgabor} 697219019Sgabor 698219019Sgabor 699219019Sgaborstatic struct full_dynamic_vlan * 700219019Sgaborfull_dynamic_vlan_init(struct hostapd_data *hapd) 701219019Sgabor{ 702219019Sgabor struct sockaddr_nl local; 703219019Sgabor struct full_dynamic_vlan *priv; 704219019Sgabor 705219019Sgabor priv = os_zalloc(sizeof(*priv)); 706219019Sgabor if (priv == NULL) 707219019Sgabor return NULL; 708219019Sgabor 709219019Sgabor#ifndef CONFIG_VLAN_NETLINK 710219019Sgabor vlan_set_name_type(hapd->conf->ssid.vlan_naming == 711219019Sgabor DYNAMIC_VLAN_NAMING_WITH_DEVICE ? 712219019Sgabor VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD : 713219019Sgabor VLAN_NAME_TYPE_PLUS_VID_NO_PAD); 714219019Sgabor#endif /* CONFIG_VLAN_NETLINK */ 715219019Sgabor 716219019Sgabor priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 717219019Sgabor if (priv->s < 0) { 718219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW," 719219019Sgabor "NETLINK_ROUTE) failed: %s", 720219019Sgabor __func__, strerror(errno)); 721219019Sgabor os_free(priv); 722219019Sgabor return NULL; 723219019Sgabor } 724219019Sgabor 725219019Sgabor os_memset(&local, 0, sizeof(local)); 726219019Sgabor local.nl_family = AF_NETLINK; 727219019Sgabor local.nl_groups = RTMGRP_LINK; 728219019Sgabor if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) { 729219019Sgabor wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s", 730219019Sgabor __func__, strerror(errno)); 731219019Sgabor close(priv->s); 732219019Sgabor os_free(priv); 733219019Sgabor return NULL; 734219019Sgabor } 735219019Sgabor 736219019Sgabor if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL)) 737219019Sgabor { 738219019Sgabor close(priv->s); 739219019Sgabor os_free(priv); 740219019Sgabor return NULL; 741219019Sgabor } 742219019Sgabor 743219019Sgabor return priv; 744219019Sgabor} 745219019Sgabor 746219019Sgabor 747219019Sgaborstatic void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv) 748219019Sgabor{ 749219019Sgabor if (priv == NULL) 750219019Sgabor return; 751219019Sgabor eloop_unregister_read_sock(priv->s); 752219019Sgabor close(priv->s); 753219019Sgabor os_free(priv); 754219019Sgabor} 755219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 756219019Sgabor 757219019Sgabor 758219019Sgaborint vlan_setup_encryption_dyn(struct hostapd_data *hapd, 759219019Sgabor struct hostapd_ssid *mssid, const char *dyn_vlan) 760219019Sgabor{ 761219019Sgabor int i; 762219019Sgabor 763219019Sgabor if (dyn_vlan == NULL) 764219019Sgabor return 0; 765219019Sgabor 766219019Sgabor /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own 767219019Sgabor * functions for setting up dynamic broadcast keys. */ 768219019Sgabor for (i = 0; i < 4; i++) { 769219019Sgabor if (mssid->wep.key[i] && 770219019Sgabor hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, 771219019Sgabor i == mssid->wep.idx, NULL, 0, 772219019Sgabor mssid->wep.key[i], mssid->wep.len[i])) 773219019Sgabor { 774219019Sgabor wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " 775219019Sgabor "encryption for dynamic VLAN"); 776219019Sgabor return -1; 777219019Sgabor } 778219019Sgabor } 779219019Sgabor 780219019Sgabor return 0; 781219019Sgabor} 782219019Sgabor 783219019Sgabor 784219019Sgaborstatic int vlan_dynamic_add(struct hostapd_data *hapd, 785219019Sgabor struct hostapd_vlan *vlan) 786219019Sgabor{ 787219019Sgabor while (vlan) { 788219019Sgabor if (vlan->vlan_id != VLAN_ID_WILDCARD) { 789219019Sgabor if (hostapd_vlan_if_add(hapd, vlan->ifname)) { 790219019Sgabor if (errno != EEXIST) { 791219019Sgabor wpa_printf(MSG_ERROR, "VLAN: Could " 792219019Sgabor "not add VLAN %s: %s", 793219019Sgabor vlan->ifname, 794219019Sgabor strerror(errno)); 795219019Sgabor return -1; 796219019Sgabor } 797219019Sgabor } 798219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 799219019Sgabor ifconfig_up(vlan->ifname); 800219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 801219019Sgabor } 802219019Sgabor 803219019Sgabor vlan = vlan->next; 804219019Sgabor } 805219019Sgabor 806219019Sgabor return 0; 807219019Sgabor} 808219019Sgabor 809219019Sgabor 810219019Sgaborstatic void vlan_dynamic_remove(struct hostapd_data *hapd, 811219019Sgabor struct hostapd_vlan *vlan) 812219019Sgabor{ 813219019Sgabor struct hostapd_vlan *next; 814219019Sgabor 815219019Sgabor while (vlan) { 816219019Sgabor next = vlan->next; 817219019Sgabor 818219019Sgabor if (vlan->vlan_id != VLAN_ID_WILDCARD && 819219019Sgabor hostapd_vlan_if_remove(hapd, vlan->ifname)) { 820219019Sgabor wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " 821219019Sgabor "iface: %s: %s", 822219019Sgabor vlan->ifname, strerror(errno)); 823219019Sgabor } 824219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 825219019Sgabor if (vlan->clean) 826219019Sgabor vlan_dellink(vlan->ifname, hapd); 827219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 828219019Sgabor 829219019Sgabor vlan = next; 830219019Sgabor } 831219019Sgabor} 832219019Sgabor 833219019Sgabor 834219019Sgaborint vlan_init(struct hostapd_data *hapd) 835219019Sgabor{ 836219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 837219019Sgabor hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); 838219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 839219019Sgabor 840219019Sgabor if (vlan_dynamic_add(hapd, hapd->conf->vlan)) 841219019Sgabor return -1; 842219019Sgabor 843219019Sgabor return 0; 844219019Sgabor} 845219019Sgabor 846219019Sgabor 847219019Sgaborvoid vlan_deinit(struct hostapd_data *hapd) 848219019Sgabor{ 849219019Sgabor vlan_dynamic_remove(hapd, hapd->conf->vlan); 850219019Sgabor 851219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 852219019Sgabor full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); 853219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 854219019Sgabor} 855219019Sgabor 856219019Sgabor 857219019Sgaborstruct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, 858219019Sgabor struct hostapd_vlan *vlan, 859219019Sgabor int vlan_id) 860219019Sgabor{ 861219019Sgabor struct hostapd_vlan *n; 862219019Sgabor char *ifname, *pos; 863219019Sgabor 864219019Sgabor if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID || 865219019Sgabor vlan->vlan_id != VLAN_ID_WILDCARD) 866219019Sgabor return NULL; 867219019Sgabor 868219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", 869219019Sgabor __func__, vlan_id, vlan->ifname); 870219019Sgabor ifname = os_strdup(vlan->ifname); 871219019Sgabor if (ifname == NULL) 872219019Sgabor return NULL; 873219019Sgabor pos = os_strchr(ifname, '#'); 874219019Sgabor if (pos == NULL) { 875219019Sgabor os_free(ifname); 876219019Sgabor return NULL; 877219019Sgabor } 878219019Sgabor *pos++ = '\0'; 879219019Sgabor 880219019Sgabor n = os_zalloc(sizeof(*n)); 881219019Sgabor if (n == NULL) { 882219019Sgabor os_free(ifname); 883219019Sgabor return NULL; 884219019Sgabor } 885219019Sgabor 886219019Sgabor n->vlan_id = vlan_id; 887219019Sgabor n->dynamic_vlan = 1; 888219019Sgabor 889219019Sgabor os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, 890219019Sgabor pos); 891219019Sgabor os_free(ifname); 892219019Sgabor 893219019Sgabor if (hostapd_vlan_if_add(hapd, n->ifname)) { 894219019Sgabor os_free(n); 895219019Sgabor return NULL; 896219019Sgabor } 897219019Sgabor 898219019Sgabor n->next = hapd->conf->vlan; 899219019Sgabor hapd->conf->vlan = n; 900219019Sgabor 901219019Sgabor#ifdef CONFIG_FULL_DYNAMIC_VLAN 902219019Sgabor ifconfig_up(n->ifname); 903219019Sgabor#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 904219019Sgabor 905219019Sgabor return n; 906219019Sgabor} 907219019Sgabor 908219019Sgabor 909219019Sgaborint vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) 910219019Sgabor{ 911219019Sgabor struct hostapd_vlan *vlan; 912219019Sgabor 913219019Sgabor if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) 914219019Sgabor return 1; 915219019Sgabor 916219019Sgabor wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); 917219019Sgabor 918219019Sgabor vlan = hapd->conf->vlan; 919219019Sgabor while (vlan) { 920219019Sgabor if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { 921219019Sgabor vlan->dynamic_vlan--; 922219019Sgabor break; 923219019Sgabor } 924219019Sgabor vlan = vlan->next; 925219019Sgabor } 926219019Sgabor 927219019Sgabor if (vlan == NULL) 928219019Sgabor return 1; 929219019Sgabor 930219019Sgabor if (vlan->dynamic_vlan == 0) 931219019Sgabor hostapd_vlan_if_remove(hapd, vlan->ifname); 932219019Sgabor 933219019Sgabor return 0; 934219019Sgabor} 935219019Sgabor