Updated to hostap_2_6
[mech_eap.git] / libeap / src / ap / vlan_init.c
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                 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 }