1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * hostapd / VLAN initialization 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 13e5b75505Sopenharmony_ci#include "utils/common.h" 14e5b75505Sopenharmony_ci#include "hostapd.h" 15e5b75505Sopenharmony_ci#include "ap_config.h" 16e5b75505Sopenharmony_ci#include "ap_drv_ops.h" 17e5b75505Sopenharmony_ci#include "wpa_auth.h" 18e5b75505Sopenharmony_ci#include "vlan_init.h" 19e5b75505Sopenharmony_ci#include "vlan_util.h" 20e5b75505Sopenharmony_ci 21e5b75505Sopenharmony_ci 22e5b75505Sopenharmony_cistatic int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, 23e5b75505Sopenharmony_ci int existsok) 24e5b75505Sopenharmony_ci{ 25e5b75505Sopenharmony_ci int ret, i; 26e5b75505Sopenharmony_ci 27e5b75505Sopenharmony_ci for (i = 0; i < NUM_WEP_KEYS; i++) { 28e5b75505Sopenharmony_ci if (!hapd->conf->ssid.wep.key[i]) 29e5b75505Sopenharmony_ci continue; 30e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 31e5b75505Sopenharmony_ci "VLAN: Refusing to set up VLAN iface %s with WEP", 32e5b75505Sopenharmony_ci vlan->ifname); 33e5b75505Sopenharmony_ci return -1; 34e5b75505Sopenharmony_ci } 35e5b75505Sopenharmony_ci 36e5b75505Sopenharmony_ci if (!iface_exists(vlan->ifname)) 37e5b75505Sopenharmony_ci ret = hostapd_vlan_if_add(hapd, vlan->ifname); 38e5b75505Sopenharmony_ci else if (!existsok) 39e5b75505Sopenharmony_ci return -1; 40e5b75505Sopenharmony_ci else 41e5b75505Sopenharmony_ci ret = 0; 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci if (ret) 44e5b75505Sopenharmony_ci return ret; 45e5b75505Sopenharmony_ci 46e5b75505Sopenharmony_ci ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */ 47e5b75505Sopenharmony_ci 48e5b75505Sopenharmony_ci if (hapd->wpa_auth) 49e5b75505Sopenharmony_ci ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id); 50e5b75505Sopenharmony_ci 51e5b75505Sopenharmony_ci if (ret == 0) 52e5b75505Sopenharmony_ci return ret; 53e5b75505Sopenharmony_ci 54e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)", 55e5b75505Sopenharmony_ci vlan->vlan_id, ret); 56e5b75505Sopenharmony_ci if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id)) 57e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname); 58e5b75505Sopenharmony_ci 59e5b75505Sopenharmony_ci /* group state machine setup failed */ 60e5b75505Sopenharmony_ci if (hostapd_vlan_if_remove(hapd, vlan->ifname)) 61e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname); 62e5b75505Sopenharmony_ci 63e5b75505Sopenharmony_ci return ret; 64e5b75505Sopenharmony_ci} 65e5b75505Sopenharmony_ci 66e5b75505Sopenharmony_ci 67e5b75505Sopenharmony_ciint vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan) 68e5b75505Sopenharmony_ci{ 69e5b75505Sopenharmony_ci int ret; 70e5b75505Sopenharmony_ci 71e5b75505Sopenharmony_ci ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id); 72e5b75505Sopenharmony_ci if (ret) 73e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 74e5b75505Sopenharmony_ci "WPA deinitialization for VLAN %d failed (%d)", 75e5b75505Sopenharmony_ci vlan->vlan_id, ret); 76e5b75505Sopenharmony_ci 77e5b75505Sopenharmony_ci return hostapd_vlan_if_remove(hapd, vlan->ifname); 78e5b75505Sopenharmony_ci} 79e5b75505Sopenharmony_ci 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_cistatic int vlan_dynamic_add(struct hostapd_data *hapd, 82e5b75505Sopenharmony_ci struct hostapd_vlan *vlan) 83e5b75505Sopenharmony_ci{ 84e5b75505Sopenharmony_ci while (vlan) { 85e5b75505Sopenharmony_ci if (vlan->vlan_id != VLAN_ID_WILDCARD) { 86e5b75505Sopenharmony_ci if (vlan_if_add(hapd, vlan, 1)) { 87e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 88e5b75505Sopenharmony_ci "VLAN: Could not add VLAN %s: %s", 89e5b75505Sopenharmony_ci vlan->ifname, strerror(errno)); 90e5b75505Sopenharmony_ci return -1; 91e5b75505Sopenharmony_ci } 92e5b75505Sopenharmony_ci#ifdef CONFIG_FULL_DYNAMIC_VLAN 93e5b75505Sopenharmony_ci vlan_newlink(vlan->ifname, hapd); 94e5b75505Sopenharmony_ci#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 95e5b75505Sopenharmony_ci } 96e5b75505Sopenharmony_ci 97e5b75505Sopenharmony_ci vlan = vlan->next; 98e5b75505Sopenharmony_ci } 99e5b75505Sopenharmony_ci 100e5b75505Sopenharmony_ci return 0; 101e5b75505Sopenharmony_ci} 102e5b75505Sopenharmony_ci 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_cistatic void vlan_dynamic_remove(struct hostapd_data *hapd, 105e5b75505Sopenharmony_ci struct hostapd_vlan *vlan) 106e5b75505Sopenharmony_ci{ 107e5b75505Sopenharmony_ci struct hostapd_vlan *next; 108e5b75505Sopenharmony_ci 109e5b75505Sopenharmony_ci while (vlan) { 110e5b75505Sopenharmony_ci next = vlan->next; 111e5b75505Sopenharmony_ci 112e5b75505Sopenharmony_ci#ifdef CONFIG_FULL_DYNAMIC_VLAN 113e5b75505Sopenharmony_ci /* vlan_dellink() takes care of cleanup and interface removal */ 114e5b75505Sopenharmony_ci if (vlan->vlan_id != VLAN_ID_WILDCARD) 115e5b75505Sopenharmony_ci vlan_dellink(vlan->ifname, hapd); 116e5b75505Sopenharmony_ci#else /* CONFIG_FULL_DYNAMIC_VLAN */ 117e5b75505Sopenharmony_ci if (vlan->vlan_id != VLAN_ID_WILDCARD && 118e5b75505Sopenharmony_ci vlan_if_remove(hapd, vlan)) { 119e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " 120e5b75505Sopenharmony_ci "iface: %s: %s", 121e5b75505Sopenharmony_ci vlan->ifname, strerror(errno)); 122e5b75505Sopenharmony_ci } 123e5b75505Sopenharmony_ci#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 124e5b75505Sopenharmony_ci 125e5b75505Sopenharmony_ci vlan = next; 126e5b75505Sopenharmony_ci } 127e5b75505Sopenharmony_ci} 128e5b75505Sopenharmony_ci 129e5b75505Sopenharmony_ci 130e5b75505Sopenharmony_ciint vlan_init(struct hostapd_data *hapd) 131e5b75505Sopenharmony_ci{ 132e5b75505Sopenharmony_ci#ifdef CONFIG_FULL_DYNAMIC_VLAN 133e5b75505Sopenharmony_ci hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); 134e5b75505Sopenharmony_ci#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 135e5b75505Sopenharmony_ci 136e5b75505Sopenharmony_ci if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED || 137e5b75505Sopenharmony_ci hapd->conf->ssid.per_sta_vif) && 138e5b75505Sopenharmony_ci !hapd->conf->vlan) { 139e5b75505Sopenharmony_ci /* dynamic vlans enabled but no (or empty) vlan_file given */ 140e5b75505Sopenharmony_ci struct hostapd_vlan *vlan; 141e5b75505Sopenharmony_ci int ret; 142e5b75505Sopenharmony_ci 143e5b75505Sopenharmony_ci vlan = os_zalloc(sizeof(*vlan)); 144e5b75505Sopenharmony_ci if (vlan == NULL) { 145e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Out of memory while assigning " 146e5b75505Sopenharmony_ci "VLAN interfaces"); 147e5b75505Sopenharmony_ci return -1; 148e5b75505Sopenharmony_ci } 149e5b75505Sopenharmony_ci 150e5b75505Sopenharmony_ci vlan->vlan_id = VLAN_ID_WILDCARD; 151e5b75505Sopenharmony_ci ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#", 152e5b75505Sopenharmony_ci hapd->conf->iface); 153e5b75505Sopenharmony_ci if (ret >= (int) sizeof(vlan->ifname)) { 154e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, 155e5b75505Sopenharmony_ci "VLAN: Interface name was truncated to %s", 156e5b75505Sopenharmony_ci vlan->ifname); 157e5b75505Sopenharmony_ci } else if (ret < 0) { 158e5b75505Sopenharmony_ci os_free(vlan); 159e5b75505Sopenharmony_ci return ret; 160e5b75505Sopenharmony_ci } 161e5b75505Sopenharmony_ci vlan->next = hapd->conf->vlan; 162e5b75505Sopenharmony_ci hapd->conf->vlan = vlan; 163e5b75505Sopenharmony_ci } 164e5b75505Sopenharmony_ci 165e5b75505Sopenharmony_ci if (vlan_dynamic_add(hapd, hapd->conf->vlan)) 166e5b75505Sopenharmony_ci return -1; 167e5b75505Sopenharmony_ci 168e5b75505Sopenharmony_ci return 0; 169e5b75505Sopenharmony_ci} 170e5b75505Sopenharmony_ci 171e5b75505Sopenharmony_ci 172e5b75505Sopenharmony_civoid vlan_deinit(struct hostapd_data *hapd) 173e5b75505Sopenharmony_ci{ 174e5b75505Sopenharmony_ci vlan_dynamic_remove(hapd, hapd->conf->vlan); 175e5b75505Sopenharmony_ci 176e5b75505Sopenharmony_ci#ifdef CONFIG_FULL_DYNAMIC_VLAN 177e5b75505Sopenharmony_ci full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); 178e5b75505Sopenharmony_ci hapd->full_dynamic_vlan = NULL; 179e5b75505Sopenharmony_ci#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 180e5b75505Sopenharmony_ci} 181e5b75505Sopenharmony_ci 182e5b75505Sopenharmony_ci 183e5b75505Sopenharmony_cistruct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, 184e5b75505Sopenharmony_ci struct hostapd_vlan *vlan, 185e5b75505Sopenharmony_ci int vlan_id, 186e5b75505Sopenharmony_ci struct vlan_description *vlan_desc) 187e5b75505Sopenharmony_ci{ 188e5b75505Sopenharmony_ci struct hostapd_vlan *n; 189e5b75505Sopenharmony_ci char ifname[IFNAMSIZ + 1], *pos; 190e5b75505Sopenharmony_ci int ret; 191e5b75505Sopenharmony_ci 192e5b75505Sopenharmony_ci if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD) 193e5b75505Sopenharmony_ci return NULL; 194e5b75505Sopenharmony_ci 195e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", 196e5b75505Sopenharmony_ci __func__, vlan_id, vlan->ifname); 197e5b75505Sopenharmony_ci os_strlcpy(ifname, vlan->ifname, sizeof(ifname)); 198e5b75505Sopenharmony_ci pos = os_strchr(ifname, '#'); 199e5b75505Sopenharmony_ci if (pos == NULL) 200e5b75505Sopenharmony_ci return NULL; 201e5b75505Sopenharmony_ci *pos++ = '\0'; 202e5b75505Sopenharmony_ci 203e5b75505Sopenharmony_ci n = os_zalloc(sizeof(*n)); 204e5b75505Sopenharmony_ci if (n == NULL) 205e5b75505Sopenharmony_ci return NULL; 206e5b75505Sopenharmony_ci 207e5b75505Sopenharmony_ci n->vlan_id = vlan_id; 208e5b75505Sopenharmony_ci if (vlan_desc) 209e5b75505Sopenharmony_ci n->vlan_desc = *vlan_desc; 210e5b75505Sopenharmony_ci n->dynamic_vlan = 1; 211e5b75505Sopenharmony_ci 212e5b75505Sopenharmony_ci ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", 213e5b75505Sopenharmony_ci ifname, vlan_id, pos); 214e5b75505Sopenharmony_ci if (os_snprintf_error(sizeof(n->ifname), ret)) { 215e5b75505Sopenharmony_ci os_free(n); 216e5b75505Sopenharmony_ci return NULL; 217e5b75505Sopenharmony_ci } 218e5b75505Sopenharmony_ci os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge)); 219e5b75505Sopenharmony_ci 220e5b75505Sopenharmony_ci n->next = hapd->conf->vlan; 221e5b75505Sopenharmony_ci hapd->conf->vlan = n; 222e5b75505Sopenharmony_ci 223e5b75505Sopenharmony_ci /* hapd->conf->vlan needs this new VLAN here for WPA setup */ 224e5b75505Sopenharmony_ci if (vlan_if_add(hapd, n, 0)) { 225e5b75505Sopenharmony_ci hapd->conf->vlan = n->next; 226e5b75505Sopenharmony_ci os_free(n); 227e5b75505Sopenharmony_ci n = NULL; 228e5b75505Sopenharmony_ci } 229e5b75505Sopenharmony_ci 230e5b75505Sopenharmony_ci return n; 231e5b75505Sopenharmony_ci} 232e5b75505Sopenharmony_ci 233e5b75505Sopenharmony_ci 234e5b75505Sopenharmony_ciint vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) 235e5b75505Sopenharmony_ci{ 236e5b75505Sopenharmony_ci struct hostapd_vlan *vlan; 237e5b75505Sopenharmony_ci 238e5b75505Sopenharmony_ci if (vlan_id <= 0) 239e5b75505Sopenharmony_ci return 1; 240e5b75505Sopenharmony_ci 241e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)", 242e5b75505Sopenharmony_ci __func__, hapd->conf->iface, vlan_id); 243e5b75505Sopenharmony_ci 244e5b75505Sopenharmony_ci vlan = hapd->conf->vlan; 245e5b75505Sopenharmony_ci while (vlan) { 246e5b75505Sopenharmony_ci if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { 247e5b75505Sopenharmony_ci vlan->dynamic_vlan--; 248e5b75505Sopenharmony_ci break; 249e5b75505Sopenharmony_ci } 250e5b75505Sopenharmony_ci vlan = vlan->next; 251e5b75505Sopenharmony_ci } 252e5b75505Sopenharmony_ci 253e5b75505Sopenharmony_ci if (vlan == NULL) 254e5b75505Sopenharmony_ci return 1; 255e5b75505Sopenharmony_ci 256e5b75505Sopenharmony_ci if (vlan->dynamic_vlan == 0) { 257e5b75505Sopenharmony_ci vlan_if_remove(hapd, vlan); 258e5b75505Sopenharmony_ci#ifdef CONFIG_FULL_DYNAMIC_VLAN 259e5b75505Sopenharmony_ci vlan_dellink(vlan->ifname, hapd); 260e5b75505Sopenharmony_ci#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 261e5b75505Sopenharmony_ci } 262e5b75505Sopenharmony_ci 263e5b75505Sopenharmony_ci return 0; 264e5b75505Sopenharmony_ci} 265