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