]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * hostapd / VLAN initialization | |
3 | * Copyright 2003, Instant802 Networks, Inc. | |
4 | * Copyright 2005-2006, Devicescape Software, Inc. | |
36592d31 | 5 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> |
6fc6879b | 6 | * |
5f9c134a JM |
7 | * This software may be distributed under the terms of the BSD license. |
8 | * See README for more details. | |
6fc6879b JM |
9 | */ |
10 | ||
6226e38d | 11 | #include "utils/includes.h" |
6fc6879b | 12 | |
6226e38d | 13 | #include "utils/common.h" |
6fc6879b | 14 | #include "hostapd.h" |
6226e38d | 15 | #include "ap_config.h" |
3acdf771 | 16 | #include "ap_drv_ops.h" |
7cebc8e2 | 17 | #include "wpa_auth.h" |
6fc6879b | 18 | #include "vlan_init.h" |
03a6a2e9 | 19 | #include "vlan_util.h" |
6fc6879b | 20 | |
6fc6879b | 21 | |
7cebc8e2 MB |
22 | static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, |
23 | int existsok) | |
24 | { | |
41d62107 MB |
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 | } | |
7cebc8e2 | 35 | |
e8685992 | 36 | if (!iface_exists(vlan->ifname)) |
7cebc8e2 MB |
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 | ||
59d63904 | 67 | int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan) |
7cebc8e2 MB |
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 | ||
6fc6879b JM |
81 | static int vlan_dynamic_add(struct hostapd_data *hapd, |
82 | struct hostapd_vlan *vlan) | |
83 | { | |
84 | while (vlan) { | |
0249c988 | 85 | if (vlan->vlan_id != VLAN_ID_WILDCARD) { |
7cebc8e2 MB |
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; | |
6fc6879b | 91 | } |
2de5a860 | 92 | #ifdef CONFIG_FULL_DYNAMIC_VLAN |
7cebc8e2 | 93 | vlan_newlink(vlan->ifname, hapd); |
2de5a860 | 94 | #endif /* CONFIG_FULL_DYNAMIC_VLAN */ |
6fc6879b JM |
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 | ||
d0bdc96b MB |
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 */ | |
6fc6879b | 117 | if (vlan->vlan_id != VLAN_ID_WILDCARD && |
7cebc8e2 | 118 | vlan_if_remove(hapd, vlan)) { |
91faf6b9 JM |
119 | wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " |
120 | "iface: %s: %s", | |
121 | vlan->ifname, strerror(errno)); | |
6fc6879b | 122 | } |
6fc6879b JM |
123 | #endif /* CONFIG_FULL_DYNAMIC_VLAN */ |
124 | ||
125 | vlan = next; | |
126 | } | |
127 | } | |
128 | ||
129 | ||
130 | int vlan_init(struct hostapd_data *hapd) | |
131 | { | |
6fc6879b JM |
132 | #ifdef CONFIG_FULL_DYNAMIC_VLAN |
133 | hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); | |
134 | #endif /* CONFIG_FULL_DYNAMIC_VLAN */ | |
135 | ||
8be640b7 MB |
136 | if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED || |
137 | hapd->conf->ssid.per_sta_vif) && | |
7ca902b5 MB |
138 | !hapd->conf->vlan) { |
139 | /* dynamic vlans enabled but no (or empty) vlan_file given */ | |
140 | struct hostapd_vlan *vlan; | |
68500d81 AO |
141 | int ret; |
142 | ||
7ca902b5 MB |
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; | |
68500d81 AO |
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 | } | |
c2db79f2 MB |
161 | vlan->next = hapd->conf->vlan; |
162 | hapd->conf->vlan = vlan; | |
7ca902b5 MB |
163 | } |
164 | ||
e34ce168 JM |
165 | if (vlan_dynamic_add(hapd, hapd->conf->vlan)) |
166 | return -1; | |
167 | ||
6fc6879b JM |
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); | |
66f4dd15 | 178 | hapd->full_dynamic_vlan = NULL; |
6fc6879b JM |
179 | #endif /* CONFIG_FULL_DYNAMIC_VLAN */ |
180 | } | |
181 | ||
182 | ||
6fc6879b JM |
183 | struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, |
184 | struct hostapd_vlan *vlan, | |
1889af2e MB |
185 | int vlan_id, |
186 | struct vlan_description *vlan_desc) | |
6fc6879b | 187 | { |
cc9c805a MB |
188 | struct hostapd_vlan *n; |
189 | char ifname[IFNAMSIZ + 1], *pos; | |
e422a819 | 190 | int ret; |
6fc6879b | 191 | |
1889af2e | 192 | if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD) |
6fc6879b JM |
193 | return NULL; |
194 | ||
91faf6b9 JM |
195 | wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", |
196 | __func__, vlan_id, vlan->ifname); | |
cc9c805a | 197 | os_strlcpy(ifname, vlan->ifname, sizeof(ifname)); |
6fc6879b | 198 | pos = os_strchr(ifname, '#'); |
66bc6830 | 199 | if (pos == NULL) |
cc9c805a | 200 | return NULL; |
6fc6879b JM |
201 | *pos++ = '\0'; |
202 | ||
203 | n = os_zalloc(sizeof(*n)); | |
66bc6830 | 204 | if (n == NULL) |
cc9c805a | 205 | return NULL; |
6fc6879b JM |
206 | |
207 | n->vlan_id = vlan_id; | |
1889af2e MB |
208 | if (vlan_desc) |
209 | n->vlan_desc = *vlan_desc; | |
6fc6879b JM |
210 | n->dynamic_vlan = 1; |
211 | ||
e422a819 JM |
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 | } | |
4d663233 | 218 | os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge)); |
6fc6879b | 219 | |
7cebc8e2 MB |
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; | |
6fc6879b | 226 | os_free(n); |
66bc6830 | 227 | n = NULL; |
6fc6879b JM |
228 | } |
229 | ||
6fc6879b JM |
230 | return n; |
231 | } | |
232 | ||
233 | ||
234 | int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) | |
235 | { | |
236 | struct hostapd_vlan *vlan; | |
237 | ||
1889af2e | 238 | if (vlan_id <= 0) |
6fc6879b JM |
239 | return 1; |
240 | ||
1acf38f1 JM |
241 | wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)", |
242 | __func__, hapd->conf->iface, vlan_id); | |
91faf6b9 | 243 | |
6fc6879b JM |
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 | ||
132dfbe8 | 256 | if (vlan->dynamic_vlan == 0) { |
7cebc8e2 | 257 | vlan_if_remove(hapd, vlan); |
132dfbe8 MB |
258 | #ifdef CONFIG_FULL_DYNAMIC_VLAN |
259 | vlan_dellink(vlan->ifname, hapd); | |
260 | #endif /* CONFIG_FULL_DYNAMIC_VLAN */ | |
261 | } | |
6fc6879b JM |
262 | |
263 | return 0; | |
264 | } |