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