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