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, 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 67 int 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 81 static 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 104 static 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 130 int 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 int ret; 142 143 vlan = os_zalloc(sizeof(*vlan)); 144 if (vlan == NULL) { 145 wpa_printf(MSG_ERROR, "Out of memory while assigning " 146 "VLAN interfaces"); 147 return -1; 148 } 149 150 vlan->vlan_id = VLAN_ID_WILDCARD; 151 ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#", 152 hapd->conf->iface); 153 if (ret >= (int) sizeof(vlan->ifname)) { 154 wpa_printf(MSG_WARNING, 155 "VLAN: Interface name was truncated to %s", 156 vlan->ifname); 157 } else if (ret < 0) { 158 os_free(vlan); 159 return ret; 160 } 161 vlan->next = hapd->conf->vlan; 162 hapd->conf->vlan = vlan; 163 } 164 165 if (vlan_dynamic_add(hapd, hapd->conf->vlan)) 166 return -1; 167 168 return 0; 169 } 170 171 172 void vlan_deinit(struct hostapd_data *hapd) 173 { 174 vlan_dynamic_remove(hapd, hapd->conf->vlan); 175 176 #ifdef CONFIG_FULL_DYNAMIC_VLAN 177 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); 178 hapd->full_dynamic_vlan = NULL; 179 #endif /* CONFIG_FULL_DYNAMIC_VLAN */ 180 } 181 182 183 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, 184 struct hostapd_vlan *vlan, 185 int vlan_id, 186 struct vlan_description *vlan_desc) 187 { 188 struct hostapd_vlan *n; 189 char ifname[IFNAMSIZ + 1], *pos; 190 191 if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD) 192 return NULL; 193 194 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", 195 __func__, vlan_id, vlan->ifname); 196 os_strlcpy(ifname, vlan->ifname, sizeof(ifname)); 197 pos = os_strchr(ifname, '#'); 198 if (pos == NULL) 199 return NULL; 200 *pos++ = '\0'; 201 202 n = os_zalloc(sizeof(*n)); 203 if (n == NULL) 204 return NULL; 205 206 n->vlan_id = vlan_id; 207 if (vlan_desc) 208 n->vlan_desc = *vlan_desc; 209 n->dynamic_vlan = 1; 210 211 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, 212 pos); 213 214 n->next = hapd->conf->vlan; 215 hapd->conf->vlan = n; 216 217 /* hapd->conf->vlan needs this new VLAN here for WPA setup */ 218 if (vlan_if_add(hapd, n, 0)) { 219 hapd->conf->vlan = n->next; 220 os_free(n); 221 n = NULL; 222 } 223 224 return n; 225 } 226 227 228 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) 229 { 230 struct hostapd_vlan *vlan; 231 232 if (vlan_id <= 0) 233 return 1; 234 235 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)", 236 __func__, hapd->conf->iface, vlan_id); 237 238 vlan = hapd->conf->vlan; 239 while (vlan) { 240 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { 241 vlan->dynamic_vlan--; 242 break; 243 } 244 vlan = vlan->next; 245 } 246 247 if (vlan == NULL) 248 return 1; 249 250 if (vlan->dynamic_vlan == 0) { 251 vlan_if_remove(hapd, vlan); 252 #ifdef CONFIG_FULL_DYNAMIC_VLAN 253 vlan_dellink(vlan->ifname, hapd); 254 #endif /* CONFIG_FULL_DYNAMIC_VLAN */ 255 } 256 257 return 0; 258 } 259