xref: /dragonfly/contrib/wpa_supplicant/src/ap/vlan_init.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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 
vlan_if_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int existsok)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 
vlan_if_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)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 
vlan_dynamic_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan)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 
vlan_dynamic_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)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 
vlan_init(struct hostapd_data * hapd)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 
vlan_deinit(struct hostapd_data * hapd)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 
vlan_add_dynamic(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vlan_id,struct vlan_description * vlan_desc)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           int ret;
191 
192           if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
193                     return NULL;
194 
195           wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
196                        __func__, vlan_id, vlan->ifname);
197           os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
198           pos = os_strchr(ifname, '#');
199           if (pos == NULL)
200                     return NULL;
201           *pos++ = '\0';
202 
203           n = os_zalloc(sizeof(*n));
204           if (n == NULL)
205                     return NULL;
206 
207           n->vlan_id = vlan_id;
208           if (vlan_desc)
209                     n->vlan_desc = *vlan_desc;
210           n->dynamic_vlan = 1;
211 
212           ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
213                                 ifname, vlan_id, pos);
214           if (os_snprintf_error(sizeof(n->ifname), ret)) {
215                     os_free(n);
216                     return NULL;
217           }
218           os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
219 
220           n->next = hapd->conf->vlan;
221           hapd->conf->vlan = n;
222 
223           /* hapd->conf->vlan needs this new VLAN here for WPA setup */
224           if (vlan_if_add(hapd, n, 0)) {
225                     hapd->conf->vlan = n->next;
226                     os_free(n);
227                     n = NULL;
228           }
229 
230           return n;
231 }
232 
233 
vlan_remove_dynamic(struct hostapd_data * hapd,int vlan_id)234 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
235 {
236           struct hostapd_vlan *vlan;
237 
238           if (vlan_id <= 0)
239                     return 1;
240 
241           wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
242                        __func__, hapd->conf->iface, vlan_id);
243 
244           vlan = hapd->conf->vlan;
245           while (vlan) {
246                     if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
247                               vlan->dynamic_vlan--;
248                               break;
249                     }
250                     vlan = vlan->next;
251           }
252 
253           if (vlan == NULL)
254                     return 1;
255 
256           if (vlan->dynamic_vlan == 0) {
257                     vlan_if_remove(hapd, vlan);
258 #ifdef CONFIG_FULL_DYNAMIC_VLAN
259                     vlan_dellink(vlan->ifname, hapd);
260 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
261           }
262 
263           return 0;
264 }
265