Home | History | Annotate | Download | only in ap
      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 (at) 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 		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 
    162 void 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 
    173 struct 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 
    218 int 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