]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * hostapd / Initialization and configuration | |
6f78f2fb | 3 | * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> |
6fc6879b JM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
6fc6879b | 16 | |
4dbfe5c5 | 17 | #include "common.h" |
6fc6879b | 18 | #include "eloop.h" |
03da66bd JM |
19 | #include "crypto/tls.h" |
20 | #include "common/ieee802_11_defs.h" | |
21 | #include "eapol_auth/eapol_auth_sm.h" | |
e0e14a7b | 22 | #include "eapol_auth/eapol_auth_sm_i.h" |
03da66bd JM |
23 | #include "radius/radius_client.h" |
24 | #include "radius/radius_server.h" | |
25 | #include "eap_server/eap_sim_db.h" | |
26 | #include "eap_server/eap.h" | |
27 | #include "eap_server/tncs.h" | |
28 | #include "l2_packet/l2_packet.h" | |
6fc6879b JM |
29 | #include "hostapd.h" |
30 | #include "ieee802_1x.h" | |
6fc6879b JM |
31 | #include "beacon.h" |
32 | #include "hw_features.h" | |
33 | #include "accounting.h" | |
6fc6879b | 34 | #include "iapp.h" |
6fc6879b | 35 | #include "ieee802_11_auth.h" |
bcd154c3 | 36 | #include "sta_flags.h" |
6fc6879b | 37 | #include "sta_info.h" |
97234b50 | 38 | #include "ap_list.h" |
bfddd95c | 39 | #include "driver_i.h" |
6fc6879b JM |
40 | #include "wpa.h" |
41 | #include "preauth.h" | |
6fc6879b JM |
42 | #include "vlan_init.h" |
43 | #include "ctrl_iface.h" | |
ad08c363 | 44 | #include "wps_hostapd.h" |
81897f4c | 45 | #include "tkip_countermeasures.h" |
6fc6879b JM |
46 | |
47 | ||
ad08c363 JM |
48 | static int hostapd_flush_old_stations(struct hostapd_data *hapd); |
49 | static int hostapd_setup_wpa(struct hostapd_data *hapd); | |
50 | static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); | |
6fc6879b | 51 | |
6fc6879b | 52 | extern int wpa_debug_level; |
6fc6879b | 53 | |
95272a88 JM |
54 | #if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) |
55 | #define EAP_SIM_DB | |
56 | #endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ | |
57 | ||
6fc6879b | 58 | |
95272a88 | 59 | #ifdef EAP_SIM_DB |
6fc6879b JM |
60 | static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd, |
61 | struct sta_info *sta, void *ctx) | |
62 | { | |
63 | if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0) | |
64 | return 1; | |
65 | return 0; | |
66 | } | |
67 | ||
68 | ||
69 | static void hostapd_sim_db_cb(void *ctx, void *session_ctx) | |
70 | { | |
71 | struct hostapd_data *hapd = ctx; | |
74784010 JM |
72 | if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) { |
73 | #ifdef RADIUS_SERVER | |
6fc6879b | 74 | radius_server_eap_pending_cb(hapd->radius_srv, session_ctx); |
74784010 JM |
75 | #endif /* RADIUS_SERVER */ |
76 | } | |
6fc6879b | 77 | } |
95272a88 | 78 | #endif /* EAP_SIM_DB */ |
6fc6879b JM |
79 | |
80 | ||
6fc6879b JM |
81 | static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, |
82 | struct wpa_auth_config *wconf) | |
83 | { | |
84 | wconf->wpa = conf->wpa; | |
85 | wconf->wpa_key_mgmt = conf->wpa_key_mgmt; | |
86 | wconf->wpa_pairwise = conf->wpa_pairwise; | |
87 | wconf->wpa_group = conf->wpa_group; | |
88 | wconf->wpa_group_rekey = conf->wpa_group_rekey; | |
89 | wconf->wpa_strict_rekey = conf->wpa_strict_rekey; | |
90 | wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; | |
581a8cde | 91 | wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; |
6fc6879b JM |
92 | wconf->rsn_pairwise = conf->rsn_pairwise; |
93 | wconf->rsn_preauth = conf->rsn_preauth; | |
94 | wconf->eapol_version = conf->eapol_version; | |
95 | wconf->peerkey = conf->peerkey; | |
3ae0800c | 96 | wconf->wmm_enabled = conf->wmm_enabled; |
bf98f7f3 | 97 | wconf->okc = conf->okc; |
6fc6879b JM |
98 | #ifdef CONFIG_IEEE80211W |
99 | wconf->ieee80211w = conf->ieee80211w; | |
100 | #endif /* CONFIG_IEEE80211W */ | |
101 | #ifdef CONFIG_IEEE80211R | |
102 | wconf->ssid_len = conf->ssid.ssid_len; | |
103 | if (wconf->ssid_len > SSID_LEN) | |
104 | wconf->ssid_len = SSID_LEN; | |
105 | os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); | |
106 | os_memcpy(wconf->mobility_domain, conf->mobility_domain, | |
107 | MOBILITY_DOMAIN_ID_LEN); | |
108 | if (conf->nas_identifier && | |
109 | os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { | |
110 | wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); | |
111 | os_memcpy(wconf->r0_key_holder, conf->nas_identifier, | |
112 | wconf->r0_key_holder_len); | |
113 | } | |
114 | os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); | |
115 | wconf->r0_key_lifetime = conf->r0_key_lifetime; | |
116 | wconf->reassociation_deadline = conf->reassociation_deadline; | |
117 | wconf->r0kh_list = conf->r0kh_list; | |
118 | wconf->r1kh_list = conf->r1kh_list; | |
119 | wconf->pmk_r1_push = conf->pmk_r1_push; | |
120 | #endif /* CONFIG_IEEE80211R */ | |
121 | } | |
122 | ||
123 | ||
ad08c363 JM |
124 | int hostapd_reload_config(struct hostapd_iface *iface) |
125 | { | |
126 | struct hostapd_data *hapd = iface->bss[0]; | |
127 | struct hostapd_config *newconf, *oldconf; | |
128 | struct wpa_auth_config wpa_auth_conf; | |
c213cc04 | 129 | size_t j; |
ad08c363 JM |
130 | |
131 | newconf = hostapd_config_read(iface->config_fname); | |
132 | if (newconf == NULL) | |
133 | return -1; | |
134 | ||
135 | /* | |
136 | * Deauthenticate all stations since the new configuration may not | |
137 | * allow them to use the BSS anymore. | |
138 | */ | |
c213cc04 JM |
139 | for (j = 0; j < iface->num_bss; j++) |
140 | hostapd_flush_old_stations(iface->bss[j]); | |
ad08c363 | 141 | |
74784010 | 142 | #ifndef CONFIG_NO_RADIUS |
ad08c363 JM |
143 | /* TODO: update dynamic data based on changed configuration |
144 | * items (e.g., open/close sockets, etc.) */ | |
145 | radius_client_flush(hapd->radius, 0); | |
74784010 | 146 | #endif /* CONFIG_NO_RADIUS */ |
ad08c363 JM |
147 | |
148 | oldconf = hapd->iconf; | |
149 | hapd->iconf = newconf; | |
150 | hapd->conf = &newconf->bss[0]; | |
151 | iface->conf = newconf; | |
152 | ||
153 | if (hostapd_setup_wpa_psk(hapd->conf)) { | |
154 | wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " | |
155 | "after reloading configuration"); | |
156 | } | |
157 | ||
158 | if (hapd->conf->wpa && hapd->wpa_auth == NULL) | |
159 | hostapd_setup_wpa(hapd); | |
160 | else if (hapd->conf->wpa) { | |
161 | hostapd_wpa_auth_conf(&newconf->bss[0], &wpa_auth_conf); | |
162 | wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); | |
163 | } else if (hapd->wpa_auth) { | |
164 | wpa_deinit(hapd->wpa_auth); | |
165 | hapd->wpa_auth = NULL; | |
166 | hostapd_set_privacy(hapd, 0); | |
167 | hostapd_setup_encryption(hapd->conf->iface, hapd); | |
168 | } | |
169 | ||
170 | ieee802_11_set_beacon(hapd); | |
171 | ||
c813b695 JM |
172 | if (hapd->conf->ssid.ssid_set && |
173 | hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, | |
174 | hapd->conf->ssid.ssid_len)) { | |
175 | wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); | |
176 | /* try to continue */ | |
177 | } | |
178 | ||
179 | if (hapd->conf->ieee802_1x || hapd->conf->wpa) | |
e3bd3912 JM |
180 | hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); |
181 | else | |
182 | hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); | |
c813b695 | 183 | |
ad08c363 JM |
184 | hostapd_config_free(oldconf); |
185 | ||
186 | wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); | |
187 | ||
188 | return 0; | |
189 | } | |
190 | ||
191 | ||
5c333467 | 192 | int handle_reload_iface(struct hostapd_iface *iface, void *ctx) |
6fc6879b | 193 | { |
5c333467 JM |
194 | if (hostapd_reload_config(iface) < 0) { |
195 | wpa_printf(MSG_WARNING, "Failed to read new configuration " | |
196 | "file - continuing with old."); | |
6fc6879b | 197 | } |
5c333467 | 198 | return 0; |
6fc6879b JM |
199 | } |
200 | ||
201 | ||
6fc6879b JM |
202 | static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, |
203 | char *ifname) | |
204 | { | |
205 | int i; | |
206 | ||
207 | for (i = 0; i < NUM_WEP_KEYS; i++) { | |
89d39d9d JM |
208 | if (hostapd_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, |
209 | i == 0 ? 1 : 0, NULL, 0, NULL, 0)) { | |
bb305cbd JM |
210 | wpa_printf(MSG_DEBUG, "Failed to clear default " |
211 | "encryption keys (ifname=%s keyidx=%d)", | |
212 | ifname, i); | |
6fc6879b JM |
213 | } |
214 | } | |
1aa5c134 JM |
215 | #ifdef CONFIG_IEEE80211W |
216 | if (hapd->conf->ieee80211w) { | |
217 | for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { | |
89d39d9d JM |
218 | if (hostapd_set_key(ifname, hapd, WPA_ALG_NONE, NULL, |
219 | i, i == 0 ? 1 : 0, NULL, 0, | |
220 | NULL, 0)) { | |
bb305cbd JM |
221 | wpa_printf(MSG_DEBUG, "Failed to clear " |
222 | "default mgmt encryption keys " | |
223 | "(ifname=%s keyidx=%d)", ifname, i); | |
1aa5c134 JM |
224 | } |
225 | } | |
226 | } | |
227 | #endif /* CONFIG_IEEE80211W */ | |
6fc6879b JM |
228 | } |
229 | ||
230 | ||
231 | static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) | |
232 | { | |
233 | hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); | |
234 | return 0; | |
235 | } | |
236 | ||
237 | ||
238 | static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) | |
239 | { | |
240 | int errors = 0, idx; | |
241 | struct hostapd_ssid *ssid = &hapd->conf->ssid; | |
242 | ||
243 | idx = ssid->wep.idx; | |
244 | if (ssid->wep.default_len && | |
89d39d9d JM |
245 | hostapd_set_key(hapd->conf->iface, |
246 | hapd, WPA_ALG_WEP, NULL, idx, idx == ssid->wep.idx, | |
247 | NULL, 0, ssid->wep.key[idx], ssid->wep.len[idx])) { | |
bb305cbd | 248 | wpa_printf(MSG_WARNING, "Could not set WEP encryption."); |
6fc6879b JM |
249 | errors++; |
250 | } | |
251 | ||
252 | if (ssid->dyn_vlan_keys) { | |
253 | size_t i; | |
254 | for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) { | |
255 | const char *ifname; | |
256 | struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i]; | |
257 | if (key == NULL) | |
258 | continue; | |
259 | ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, | |
260 | i); | |
261 | if (ifname == NULL) | |
262 | continue; | |
263 | ||
264 | idx = key->idx; | |
89d39d9d JM |
265 | if (hostapd_set_key(ifname, hapd, WPA_ALG_WEP, NULL, |
266 | idx, idx == key->idx, NULL, 0, | |
267 | key->key[idx], key->len[idx])) { | |
bb305cbd JM |
268 | wpa_printf(MSG_WARNING, "Could not set " |
269 | "dynamic VLAN WEP encryption."); | |
6fc6879b JM |
270 | errors++; |
271 | } | |
272 | } | |
273 | } | |
274 | ||
275 | return errors; | |
276 | } | |
277 | ||
278 | /** | |
279 | * hostapd_cleanup - Per-BSS cleanup (deinitialization) | |
280 | * @hapd: Pointer to BSS data | |
281 | * | |
282 | * This function is used to free all per-BSS data structures and resources. | |
283 | * This gets called in a loop for each BSS between calls to | |
284 | * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface | |
285 | * is deinitialized. Most of the modules that are initialized in | |
286 | * hostapd_setup_bss() are deinitialized here. | |
287 | */ | |
288 | static void hostapd_cleanup(struct hostapd_data *hapd) | |
289 | { | |
290 | hostapd_ctrl_iface_deinit(hapd); | |
291 | ||
6fc6879b JM |
292 | iapp_deinit(hapd->iapp); |
293 | hapd->iapp = NULL; | |
294 | accounting_deinit(hapd); | |
295 | rsn_preauth_iface_deinit(hapd); | |
296 | if (hapd->wpa_auth) { | |
297 | wpa_deinit(hapd->wpa_auth); | |
298 | hapd->wpa_auth = NULL; | |
299 | ||
300 | if (hostapd_set_privacy(hapd, 0)) { | |
301 | wpa_printf(MSG_DEBUG, "Could not disable " | |
302 | "PrivacyInvoked for interface %s", | |
303 | hapd->conf->iface); | |
304 | } | |
305 | ||
306 | if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { | |
307 | wpa_printf(MSG_DEBUG, "Could not remove generic " | |
308 | "information element from interface %s", | |
309 | hapd->conf->iface); | |
310 | } | |
311 | } | |
312 | ieee802_1x_deinit(hapd); | |
313 | vlan_deinit(hapd); | |
314 | hostapd_acl_deinit(hapd); | |
74784010 | 315 | #ifndef CONFIG_NO_RADIUS |
6fc6879b JM |
316 | radius_client_deinit(hapd->radius); |
317 | hapd->radius = NULL; | |
74784010 JM |
318 | #endif /* CONFIG_NO_RADIUS */ |
319 | #ifdef RADIUS_SERVER | |
6fc6879b JM |
320 | radius_server_deinit(hapd->radius_srv); |
321 | hapd->radius_srv = NULL; | |
74784010 | 322 | #endif /* RADIUS_SERVER */ |
6fc6879b JM |
323 | |
324 | #ifdef CONFIG_IEEE80211R | |
325 | l2_packet_deinit(hapd->l2); | |
326 | #endif /* CONFIG_IEEE80211R */ | |
327 | ||
ad08c363 JM |
328 | hostapd_deinit_wps(hapd); |
329 | ||
6fc6879b JM |
330 | #ifdef EAP_TLS_FUNCS |
331 | if (hapd->ssl_ctx) { | |
332 | tls_deinit(hapd->ssl_ctx); | |
333 | hapd->ssl_ctx = NULL; | |
334 | } | |
335 | #endif /* EAP_TLS_FUNCS */ | |
336 | ||
5c90d476 | 337 | #if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) |
6fc6879b JM |
338 | if (hapd->eap_sim_db_priv) { |
339 | eap_sim_db_deinit(hapd->eap_sim_db_priv); | |
340 | hapd->eap_sim_db_priv = NULL; | |
341 | } | |
5c90d476 | 342 | #endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ |
6fc6879b JM |
343 | |
344 | if (hapd->interface_added && | |
22a7c9d7 | 345 | hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { |
bb305cbd JM |
346 | wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", |
347 | hapd->conf->iface); | |
6fc6879b | 348 | } |
fa16028d JM |
349 | |
350 | os_free(hapd->probereq_cb); | |
351 | hapd->probereq_cb = NULL; | |
6fc6879b JM |
352 | } |
353 | ||
354 | ||
355 | /** | |
356 | * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup | |
357 | * @iface: Pointer to interface data | |
358 | * | |
359 | * This function is called before per-BSS data structures are deinitialized | |
360 | * with hostapd_cleanup(). | |
361 | */ | |
362 | static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface) | |
363 | { | |
364 | } | |
365 | ||
366 | ||
367 | /** | |
368 | * hostapd_cleanup_iface - Complete per-interface cleanup | |
369 | * @iface: Pointer to interface data | |
370 | * | |
371 | * This function is called after per-BSS data structures are deinitialized | |
372 | * with hostapd_cleanup(). | |
373 | */ | |
374 | static void hostapd_cleanup_iface(struct hostapd_iface *iface) | |
375 | { | |
376 | hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); | |
377 | iface->hw_features = NULL; | |
378 | os_free(iface->current_rates); | |
379 | iface->current_rates = NULL; | |
380 | ap_list_deinit(iface); | |
381 | hostapd_config_free(iface->conf); | |
382 | iface->conf = NULL; | |
383 | ||
384 | os_free(iface->config_fname); | |
385 | os_free(iface->bss); | |
386 | os_free(iface); | |
387 | } | |
388 | ||
389 | ||
390 | static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) | |
391 | { | |
392 | int i; | |
393 | ||
394 | hostapd_broadcast_wep_set(hapd); | |
395 | ||
396 | if (hapd->conf->ssid.wep.default_len) | |
397 | return 0; | |
398 | ||
399 | for (i = 0; i < 4; i++) { | |
400 | if (hapd->conf->ssid.wep.key[i] && | |
89d39d9d JM |
401 | hostapd_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, |
402 | i == hapd->conf->ssid.wep.idx, NULL, 0, | |
403 | hapd->conf->ssid.wep.key[i], | |
404 | hapd->conf->ssid.wep.len[i])) { | |
bb305cbd JM |
405 | wpa_printf(MSG_WARNING, "Could not set WEP " |
406 | "encryption."); | |
6fc6879b JM |
407 | return -1; |
408 | } | |
409 | if (hapd->conf->ssid.wep.key[i] && | |
410 | i == hapd->conf->ssid.wep.idx) | |
411 | hostapd_set_privacy(hapd, 1); | |
412 | } | |
413 | ||
414 | return 0; | |
415 | } | |
416 | ||
417 | ||
418 | static int hostapd_flush_old_stations(struct hostapd_data *hapd) | |
419 | { | |
420 | int ret = 0; | |
421 | ||
85141289 JM |
422 | if (hostapd_drv_none(hapd)) |
423 | return 0; | |
424 | ||
6fc6879b JM |
425 | wpa_printf(MSG_DEBUG, "Flushing old station entries"); |
426 | if (hostapd_flush(hapd)) { | |
bb305cbd | 427 | wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); |
6fc6879b JM |
428 | ret = -1; |
429 | } | |
430 | wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); | |
9302c5e1 JM |
431 | |
432 | /* New Prism2.5/3 STA firmware versions seem to have issues with this | |
433 | * broadcast deauth frame. This gets the firmware in odd state where | |
434 | * nothing works correctly, so let's skip sending this for the hostap | |
435 | * driver. */ | |
436 | if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) { | |
437 | u8 addr[ETH_ALEN]; | |
438 | os_memset(addr, 0xff, ETH_ALEN); | |
439 | hostapd_sta_deauth(hapd, addr, | |
440 | WLAN_REASON_PREV_AUTH_NOT_VALID); | |
441 | } | |
6fc6879b JM |
442 | |
443 | return ret; | |
444 | } | |
445 | ||
446 | ||
447 | static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, | |
448 | logger_level level, const char *txt) | |
449 | { | |
71f04b3c | 450 | #ifndef CONFIG_NO_HOSTAPD_LOGGER |
6fc6879b JM |
451 | struct hostapd_data *hapd = ctx; |
452 | int hlevel; | |
453 | ||
454 | switch (level) { | |
455 | case LOGGER_WARNING: | |
456 | hlevel = HOSTAPD_LEVEL_WARNING; | |
457 | break; | |
458 | case LOGGER_INFO: | |
459 | hlevel = HOSTAPD_LEVEL_INFO; | |
460 | break; | |
461 | case LOGGER_DEBUG: | |
462 | default: | |
463 | hlevel = HOSTAPD_LEVEL_DEBUG; | |
464 | break; | |
465 | } | |
466 | ||
467 | hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); | |
71f04b3c | 468 | #endif /* CONFIG_NO_HOSTAPD_LOGGER */ |
6fc6879b JM |
469 | } |
470 | ||
471 | ||
472 | static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, | |
473 | u16 reason) | |
474 | { | |
475 | struct hostapd_data *hapd = ctx; | |
476 | struct sta_info *sta; | |
477 | ||
478 | wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " | |
479 | "STA " MACSTR " reason %d", | |
480 | __func__, MAC2STR(addr), reason); | |
481 | ||
482 | sta = ap_get_sta(hapd, addr); | |
483 | hostapd_sta_deauth(hapd, addr, reason); | |
484 | if (sta == NULL) | |
485 | return; | |
486 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED); | |
487 | eloop_cancel_timeout(ap_handle_timer, hapd, sta); | |
488 | eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta); | |
489 | sta->timeout_next = STA_REMOVE; | |
490 | } | |
491 | ||
492 | ||
493 | static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) | |
494 | { | |
495 | struct hostapd_data *hapd = ctx; | |
81897f4c | 496 | michael_mic_failure(hapd, addr, 0); |
6fc6879b JM |
497 | } |
498 | ||
499 | ||
500 | static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, | |
501 | wpa_eapol_variable var, int value) | |
502 | { | |
503 | struct hostapd_data *hapd = ctx; | |
504 | struct sta_info *sta = ap_get_sta(hapd, addr); | |
505 | if (sta == NULL) | |
506 | return; | |
507 | switch (var) { | |
508 | case WPA_EAPOL_portEnabled: | |
509 | ieee802_1x_notify_port_enabled(sta->eapol_sm, value); | |
510 | break; | |
511 | case WPA_EAPOL_portValid: | |
512 | ieee802_1x_notify_port_valid(sta->eapol_sm, value); | |
513 | break; | |
514 | case WPA_EAPOL_authorized: | |
515 | ieee802_1x_set_sta_authorized(hapd, sta, value); | |
516 | break; | |
517 | case WPA_EAPOL_portControl_Auto: | |
518 | if (sta->eapol_sm) | |
519 | sta->eapol_sm->portControl = Auto; | |
520 | break; | |
521 | case WPA_EAPOL_keyRun: | |
522 | if (sta->eapol_sm) | |
523 | sta->eapol_sm->keyRun = value ? TRUE : FALSE; | |
524 | break; | |
525 | case WPA_EAPOL_keyAvailable: | |
526 | if (sta->eapol_sm) | |
527 | sta->eapol_sm->eap_if->eapKeyAvailable = | |
528 | value ? TRUE : FALSE; | |
529 | break; | |
530 | case WPA_EAPOL_keyDone: | |
531 | if (sta->eapol_sm) | |
532 | sta->eapol_sm->keyDone = value ? TRUE : FALSE; | |
533 | break; | |
534 | case WPA_EAPOL_inc_EapolFramesTx: | |
535 | if (sta->eapol_sm) | |
536 | sta->eapol_sm->dot1xAuthEapolFramesTx++; | |
537 | break; | |
538 | } | |
539 | } | |
540 | ||
541 | ||
542 | static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, | |
543 | wpa_eapol_variable var) | |
544 | { | |
545 | struct hostapd_data *hapd = ctx; | |
546 | struct sta_info *sta = ap_get_sta(hapd, addr); | |
547 | if (sta == NULL || sta->eapol_sm == NULL) | |
548 | return -1; | |
549 | switch (var) { | |
550 | case WPA_EAPOL_keyRun: | |
551 | return sta->eapol_sm->keyRun; | |
552 | case WPA_EAPOL_keyAvailable: | |
553 | return sta->eapol_sm->eap_if->eapKeyAvailable; | |
554 | default: | |
555 | return -1; | |
556 | } | |
557 | } | |
558 | ||
559 | ||
560 | static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, | |
561 | const u8 *prev_psk) | |
562 | { | |
563 | struct hostapd_data *hapd = ctx; | |
564 | return hostapd_get_psk(hapd->conf, addr, prev_psk); | |
565 | } | |
566 | ||
567 | ||
568 | static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, | |
569 | size_t *len) | |
570 | { | |
571 | struct hostapd_data *hapd = ctx; | |
572 | const u8 *key; | |
573 | size_t keylen; | |
574 | struct sta_info *sta; | |
575 | ||
576 | sta = ap_get_sta(hapd, addr); | |
577 | if (sta == NULL) | |
578 | return -1; | |
579 | ||
580 | key = ieee802_1x_get_key(sta->eapol_sm, &keylen); | |
581 | if (key == NULL) | |
582 | return -1; | |
583 | ||
584 | if (keylen > *len) | |
585 | keylen = *len; | |
586 | os_memcpy(msk, key, keylen); | |
587 | *len = keylen; | |
588 | ||
589 | return 0; | |
590 | } | |
591 | ||
592 | ||
89d39d9d | 593 | static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, wpa_alg alg, |
6fc6879b JM |
594 | const u8 *addr, int idx, u8 *key, |
595 | size_t key_len) | |
596 | { | |
597 | struct hostapd_data *hapd = ctx; | |
598 | const char *ifname = hapd->conf->iface; | |
599 | ||
600 | if (vlan_id > 0) { | |
601 | ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); | |
602 | if (ifname == NULL) | |
603 | return -1; | |
604 | } | |
605 | ||
89d39d9d JM |
606 | return hostapd_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, |
607 | key, key_len); | |
6fc6879b JM |
608 | } |
609 | ||
610 | ||
611 | static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, | |
612 | u8 *seq) | |
613 | { | |
614 | struct hostapd_data *hapd = ctx; | |
615 | return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); | |
616 | } | |
617 | ||
618 | ||
6fc6879b JM |
619 | static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, |
620 | const u8 *data, size_t data_len, | |
621 | int encrypt) | |
622 | { | |
623 | struct hostapd_data *hapd = ctx; | |
624 | return hostapd_send_eapol(hapd, addr, data, data_len, encrypt); | |
625 | } | |
626 | ||
627 | ||
628 | static int hostapd_wpa_auth_for_each_sta( | |
629 | void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), | |
630 | void *cb_ctx) | |
631 | { | |
632 | struct hostapd_data *hapd = ctx; | |
633 | struct sta_info *sta; | |
634 | ||
635 | for (sta = hapd->sta_list; sta; sta = sta->next) { | |
636 | if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) | |
637 | return 1; | |
638 | } | |
639 | return 0; | |
640 | } | |
641 | ||
642 | ||
5c333467 JM |
643 | struct wpa_auth_iface_iter_data { |
644 | int (*cb)(struct wpa_authenticator *sm, void *ctx); | |
645 | void *cb_ctx; | |
646 | }; | |
647 | ||
648 | static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) | |
649 | { | |
650 | struct wpa_auth_iface_iter_data *data = ctx; | |
651 | size_t i; | |
652 | for (i = 0; i < iface->num_bss; i++) { | |
653 | if (data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) | |
654 | return 1; | |
655 | } | |
656 | return 0; | |
657 | } | |
658 | ||
659 | ||
bf98f7f3 JM |
660 | static int hostapd_wpa_auth_for_each_auth( |
661 | void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), | |
662 | void *cb_ctx) | |
663 | { | |
5c333467 JM |
664 | struct wpa_auth_iface_iter_data data; |
665 | data.cb = cb; | |
666 | data.cb_ctx = cb_ctx; | |
667 | return hostapd_for_each_interface(wpa_auth_iface_iter, &data); | |
bf98f7f3 JM |
668 | } |
669 | ||
670 | ||
6fc6879b JM |
671 | static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, |
672 | const u8 *data, size_t data_len) | |
673 | { | |
674 | struct hostapd_data *hapd = ctx; | |
675 | ||
676 | if (hapd->driver && hapd->driver->send_ether) | |
677 | return hapd->driver->send_ether(hapd->drv_priv, dst, | |
678 | hapd->own_addr, proto, | |
679 | data, data_len); | |
680 | if (hapd->l2 == NULL) | |
681 | return -1; | |
682 | return l2_packet_send(hapd->l2, dst, proto, data, data_len); | |
683 | } | |
684 | ||
685 | ||
686 | #ifdef CONFIG_IEEE80211R | |
687 | ||
688 | static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, | |
689 | const u8 *data, size_t data_len) | |
690 | { | |
691 | struct hostapd_data *hapd = ctx; | |
692 | int res; | |
693 | struct ieee80211_mgmt *m; | |
694 | size_t mlen; | |
695 | struct sta_info *sta; | |
696 | ||
697 | sta = ap_get_sta(hapd, dst); | |
698 | if (sta == NULL || sta->wpa_sm == NULL) | |
699 | return -1; | |
700 | ||
701 | m = os_zalloc(sizeof(*m) + data_len); | |
702 | if (m == NULL) | |
703 | return -1; | |
704 | mlen = ((u8 *) &m->u - (u8 *) m) + data_len; | |
705 | m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, | |
706 | WLAN_FC_STYPE_ACTION); | |
707 | os_memcpy(m->da, dst, ETH_ALEN); | |
708 | os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); | |
709 | os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); | |
710 | os_memcpy(&m->u, data, data_len); | |
711 | ||
83421302 | 712 | res = hostapd_send_mgmt_frame(hapd, (u8 *) m, mlen); |
6fc6879b JM |
713 | os_free(m); |
714 | return res; | |
715 | } | |
716 | ||
717 | ||
718 | static struct wpa_state_machine * | |
719 | hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) | |
720 | { | |
721 | struct hostapd_data *hapd = ctx; | |
722 | struct sta_info *sta; | |
723 | ||
724 | sta = ap_sta_add(hapd, sta_addr); | |
725 | if (sta == NULL) | |
726 | return NULL; | |
727 | if (sta->wpa_sm) | |
728 | return sta->wpa_sm; | |
729 | ||
730 | sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); | |
731 | if (sta->wpa_sm == NULL) { | |
732 | ap_free_sta(hapd, sta); | |
733 | return NULL; | |
734 | } | |
735 | sta->auth_alg = WLAN_AUTH_FT; | |
736 | ||
737 | return sta->wpa_sm; | |
738 | } | |
739 | ||
740 | ||
741 | static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, | |
742 | size_t len) | |
743 | { | |
744 | struct hostapd_data *hapd = ctx; | |
745 | wpa_ft_rrb_rx(hapd->wpa_auth, src_addr, buf, len); | |
746 | } | |
747 | ||
748 | #endif /* CONFIG_IEEE80211R */ | |
749 | ||
750 | ||
751 | /** | |
752 | * hostapd_validate_bssid_configuration - Validate BSSID configuration | |
753 | * @iface: Pointer to interface data | |
754 | * Returns: 0 on success, -1 on failure | |
755 | * | |
756 | * This function is used to validate that the configured BSSIDs are valid. | |
757 | */ | |
758 | static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) | |
759 | { | |
760 | u8 mask[ETH_ALEN] = { 0 }; | |
761 | struct hostapd_data *hapd = iface->bss[0]; | |
762 | unsigned int i = iface->conf->num_bss, bits = 0, j; | |
763 | int res; | |
90ac1f9f | 764 | int auto_addr = 0; |
6fc6879b | 765 | |
85141289 JM |
766 | if (hostapd_drv_none(hapd)) |
767 | return 0; | |
768 | ||
6fc6879b JM |
769 | /* Generate BSSID mask that is large enough to cover the BSSIDs. */ |
770 | ||
771 | /* Determine the bits necessary to cover the number of BSSIDs. */ | |
772 | for (i--; i; i >>= 1) | |
773 | bits++; | |
774 | ||
775 | /* Determine the bits necessary to any configured BSSIDs, | |
776 | if they are higher than the number of BSSIDs. */ | |
777 | for (j = 0; j < iface->conf->num_bss; j++) { | |
90ac1f9f JM |
778 | if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) { |
779 | if (j) | |
780 | auto_addr++; | |
6fc6879b | 781 | continue; |
90ac1f9f | 782 | } |
6fc6879b JM |
783 | |
784 | for (i = 0; i < ETH_ALEN; i++) { | |
785 | mask[i] |= | |
786 | iface->conf->bss[j].bssid[i] ^ | |
787 | hapd->own_addr[i]; | |
788 | } | |
789 | } | |
790 | ||
90ac1f9f JM |
791 | if (!auto_addr) |
792 | goto skip_mask_ext; | |
793 | ||
6fc6879b JM |
794 | for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) |
795 | ; | |
796 | j = 0; | |
797 | if (i < ETH_ALEN) { | |
798 | j = (5 - i) * 8; | |
799 | ||
800 | while (mask[i] != 0) { | |
801 | mask[i] >>= 1; | |
802 | j++; | |
803 | } | |
804 | } | |
805 | ||
806 | if (bits < j) | |
807 | bits = j; | |
808 | ||
90ac1f9f JM |
809 | if (bits > 40) { |
810 | wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", | |
811 | bits); | |
6fc6879b | 812 | return -1; |
90ac1f9f | 813 | } |
6fc6879b JM |
814 | |
815 | os_memset(mask, 0xff, ETH_ALEN); | |
816 | j = bits / 8; | |
817 | for (i = 5; i > 5 - j; i--) | |
818 | mask[i] = 0; | |
819 | j = bits % 8; | |
820 | while (j--) | |
821 | mask[i] <<= 1; | |
822 | ||
90ac1f9f | 823 | skip_mask_ext: |
6fc6879b JM |
824 | wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", |
825 | (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); | |
826 | ||
827 | res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); | |
828 | if (res == 0) | |
829 | return 0; | |
830 | ||
831 | if (res < 0) { | |
bb305cbd JM |
832 | wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " |
833 | MACSTR " for start address " MACSTR ".", | |
834 | MAC2STR(mask), MAC2STR(hapd->own_addr)); | |
6fc6879b JM |
835 | return -1; |
836 | } | |
837 | ||
90ac1f9f JM |
838 | if (!auto_addr) |
839 | return 0; | |
840 | ||
6fc6879b JM |
841 | for (i = 0; i < ETH_ALEN; i++) { |
842 | if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { | |
bb305cbd JM |
843 | wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR |
844 | " for start address " MACSTR ".", | |
845 | MAC2STR(mask), MAC2STR(hapd->own_addr)); | |
846 | wpa_printf(MSG_ERROR, "Start address must be the " | |
847 | "first address in the block (i.e., addr " | |
848 | "AND mask == addr)."); | |
6fc6879b JM |
849 | return -1; |
850 | } | |
851 | } | |
852 | ||
853 | return 0; | |
854 | } | |
855 | ||
856 | ||
857 | static int mac_in_conf(struct hostapd_config *conf, const void *a) | |
858 | { | |
859 | size_t i; | |
860 | ||
861 | for (i = 0; i < conf->num_bss; i++) { | |
862 | if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) { | |
863 | return 1; | |
864 | } | |
865 | } | |
866 | ||
867 | return 0; | |
868 | } | |
869 | ||
870 | ||
871 | static int hostapd_setup_wpa(struct hostapd_data *hapd) | |
872 | { | |
873 | struct wpa_auth_config _conf; | |
874 | struct wpa_auth_callbacks cb; | |
875 | const u8 *wpa_ie; | |
876 | size_t wpa_ie_len; | |
877 | ||
878 | hostapd_wpa_auth_conf(hapd->conf, &_conf); | |
879 | os_memset(&cb, 0, sizeof(cb)); | |
880 | cb.ctx = hapd; | |
881 | cb.logger = hostapd_wpa_auth_logger; | |
882 | cb.disconnect = hostapd_wpa_auth_disconnect; | |
883 | cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report; | |
884 | cb.set_eapol = hostapd_wpa_auth_set_eapol; | |
885 | cb.get_eapol = hostapd_wpa_auth_get_eapol; | |
886 | cb.get_psk = hostapd_wpa_auth_get_psk; | |
887 | cb.get_msk = hostapd_wpa_auth_get_msk; | |
888 | cb.set_key = hostapd_wpa_auth_set_key; | |
889 | cb.get_seqnum = hostapd_wpa_auth_get_seqnum; | |
6fc6879b JM |
890 | cb.send_eapol = hostapd_wpa_auth_send_eapol; |
891 | cb.for_each_sta = hostapd_wpa_auth_for_each_sta; | |
bf98f7f3 | 892 | cb.for_each_auth = hostapd_wpa_auth_for_each_auth; |
6fc6879b JM |
893 | cb.send_ether = hostapd_wpa_auth_send_ether; |
894 | #ifdef CONFIG_IEEE80211R | |
895 | cb.send_ft_action = hostapd_wpa_auth_send_ft_action; | |
896 | cb.add_sta = hostapd_wpa_auth_add_sta; | |
897 | #endif /* CONFIG_IEEE80211R */ | |
898 | hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb); | |
899 | if (hapd->wpa_auth == NULL) { | |
bb305cbd | 900 | wpa_printf(MSG_ERROR, "WPA initialization failed."); |
6fc6879b JM |
901 | return -1; |
902 | } | |
903 | ||
904 | if (hostapd_set_privacy(hapd, 1)) { | |
905 | wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " | |
906 | "for interface %s", hapd->conf->iface); | |
907 | return -1; | |
908 | } | |
909 | ||
910 | wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); | |
911 | if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { | |
912 | wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " | |
913 | "the kernel driver."); | |
914 | return -1; | |
915 | } | |
916 | ||
917 | if (rsn_preauth_iface_init(hapd)) { | |
bb305cbd JM |
918 | wpa_printf(MSG_ERROR, "Initialization of RSN " |
919 | "pre-authentication failed."); | |
6fc6879b JM |
920 | return -1; |
921 | } | |
922 | ||
923 | return 0; | |
924 | ||
925 | } | |
926 | ||
927 | ||
74784010 JM |
928 | #ifdef RADIUS_SERVER |
929 | ||
930 | static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, | |
931 | size_t identity_len, int phase2, | |
932 | struct eap_user *user) | |
933 | { | |
934 | const struct hostapd_eap_user *eap_user; | |
935 | int i, count; | |
936 | ||
937 | eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); | |
938 | if (eap_user == NULL) | |
939 | return -1; | |
940 | ||
941 | if (user == NULL) | |
942 | return 0; | |
943 | ||
944 | os_memset(user, 0, sizeof(*user)); | |
945 | count = EAP_USER_MAX_METHODS; | |
946 | if (count > EAP_MAX_METHODS) | |
947 | count = EAP_MAX_METHODS; | |
948 | for (i = 0; i < count; i++) { | |
949 | user->methods[i].vendor = eap_user->methods[i].vendor; | |
950 | user->methods[i].method = eap_user->methods[i].method; | |
951 | } | |
952 | ||
953 | if (eap_user->password) { | |
954 | user->password = os_malloc(eap_user->password_len); | |
955 | if (user->password == NULL) | |
956 | return -1; | |
957 | os_memcpy(user->password, eap_user->password, | |
958 | eap_user->password_len); | |
959 | user->password_len = eap_user->password_len; | |
960 | user->password_hash = eap_user->password_hash; | |
961 | } | |
962 | user->force_version = eap_user->force_version; | |
963 | user->ttls_auth = eap_user->ttls_auth; | |
964 | ||
965 | return 0; | |
966 | } | |
967 | ||
968 | ||
6fc6879b JM |
969 | static int hostapd_setup_radius_srv(struct hostapd_data *hapd, |
970 | struct hostapd_bss_config *conf) | |
971 | { | |
972 | struct radius_server_conf srv; | |
973 | os_memset(&srv, 0, sizeof(srv)); | |
974 | srv.client_file = conf->radius_server_clients; | |
975 | srv.auth_port = conf->radius_server_auth_port; | |
976 | srv.conf_ctx = conf; | |
977 | srv.eap_sim_db_priv = hapd->eap_sim_db_priv; | |
978 | srv.ssl_ctx = hapd->ssl_ctx; | |
979 | srv.pac_opaque_encr_key = conf->pac_opaque_encr_key; | |
980 | srv.eap_fast_a_id = conf->eap_fast_a_id; | |
2d867244 JM |
981 | srv.eap_fast_a_id_len = conf->eap_fast_a_id_len; |
982 | srv.eap_fast_a_id_info = conf->eap_fast_a_id_info; | |
378eae5e | 983 | srv.eap_fast_prov = conf->eap_fast_prov; |
a11c90a6 JM |
984 | srv.pac_key_lifetime = conf->pac_key_lifetime; |
985 | srv.pac_key_refresh_time = conf->pac_key_refresh_time; | |
6fc6879b | 986 | srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; |
c3e258ae | 987 | srv.tnc = conf->tnc; |
ad08c363 | 988 | srv.wps = hapd->wps; |
6fc6879b JM |
989 | srv.ipv6 = conf->radius_server_ipv6; |
990 | srv.get_eap_user = hostapd_radius_get_eap_user; | |
65d50f0a JM |
991 | srv.eap_req_id_text = conf->eap_req_id_text; |
992 | srv.eap_req_id_text_len = conf->eap_req_id_text_len; | |
6fc6879b JM |
993 | |
994 | hapd->radius_srv = radius_server_init(&srv); | |
995 | if (hapd->radius_srv == NULL) { | |
bb305cbd | 996 | wpa_printf(MSG_ERROR, "RADIUS server initialization failed."); |
6fc6879b JM |
997 | return -1; |
998 | } | |
999 | ||
1000 | return 0; | |
1001 | } | |
1002 | ||
74784010 JM |
1003 | #endif /* RADIUS_SERVER */ |
1004 | ||
6fc6879b JM |
1005 | |
1006 | /** | |
1007 | * hostapd_setup_bss - Per-BSS setup (initialization) | |
1008 | * @hapd: Pointer to BSS data | |
1009 | * @first: Whether this BSS is the first BSS of an interface | |
1010 | * | |
1011 | * This function is used to initialize all per-BSS data structures and | |
1012 | * resources. This gets called in a loop for each BSS when an interface is | |
1013 | * initialized. Most of the modules that are initialized here will be | |
1014 | * deinitialized in hostapd_cleanup(). | |
1015 | */ | |
1016 | static int hostapd_setup_bss(struct hostapd_data *hapd, int first) | |
1017 | { | |
1018 | struct hostapd_bss_config *conf = hapd->conf; | |
1019 | u8 ssid[HOSTAPD_MAX_SSID_LEN + 1]; | |
1020 | int ssid_len, set_ssid; | |
1021 | ||
1022 | if (!first) { | |
1023 | if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) { | |
1024 | /* Allocate the next available BSSID. */ | |
1025 | do { | |
1026 | inc_byte_array(hapd->own_addr, ETH_ALEN); | |
1027 | } while (mac_in_conf(hapd->iconf, hapd->own_addr)); | |
1028 | } else { | |
1029 | /* Allocate the configured BSSID. */ | |
1030 | os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); | |
1031 | ||
1032 | if (hostapd_mac_comp(hapd->own_addr, | |
1033 | hapd->iface->bss[0]->own_addr) == | |
1034 | 0) { | |
bb305cbd JM |
1035 | wpa_printf(MSG_ERROR, "BSS '%s' may not have " |
1036 | "BSSID set to the MAC address of " | |
1037 | "the radio", hapd->conf->iface); | |
6fc6879b JM |
1038 | return -1; |
1039 | } | |
1040 | } | |
1041 | ||
1042 | hapd->interface_added = 1; | |
22a7c9d7 JM |
1043 | if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, |
1044 | hapd->conf->iface, hapd->own_addr)) { | |
bb305cbd JM |
1045 | wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" |
1046 | MACSTR ")", MAC2STR(hapd->own_addr)); | |
6fc6879b JM |
1047 | return -1; |
1048 | } | |
1049 | } | |
1050 | ||
c213cc04 JM |
1051 | hostapd_flush_old_stations(hapd); |
1052 | hostapd_set_privacy(hapd, 0); | |
1053 | ||
1054 | hostapd_broadcast_wep_clear(hapd); | |
1055 | if (hostapd_setup_encryption(hapd->conf->iface, hapd)) | |
1056 | return -1; | |
1057 | ||
6fc6879b JM |
1058 | /* |
1059 | * Fetch the SSID from the system and use it or, | |
1060 | * if one was specified in the config file, verify they | |
1061 | * match. | |
1062 | */ | |
1063 | ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); | |
1064 | if (ssid_len < 0) { | |
bb305cbd | 1065 | wpa_printf(MSG_ERROR, "Could not read SSID from system"); |
6fc6879b JM |
1066 | return -1; |
1067 | } | |
1068 | if (conf->ssid.ssid_set) { | |
1069 | /* | |
1070 | * If SSID is specified in the config file and it differs | |
1071 | * from what is being used then force installation of the | |
1072 | * new SSID. | |
1073 | */ | |
1074 | set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || | |
1075 | os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); | |
1076 | } else { | |
1077 | /* | |
1078 | * No SSID in the config file; just use the one we got | |
1079 | * from the system. | |
1080 | */ | |
1081 | set_ssid = 0; | |
1082 | conf->ssid.ssid_len = ssid_len; | |
1083 | os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); | |
1084 | conf->ssid.ssid[conf->ssid.ssid_len] = '\0'; | |
1085 | } | |
1086 | ||
85141289 | 1087 | if (!hostapd_drv_none(hapd)) { |
bb305cbd JM |
1088 | wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR |
1089 | " and ssid '%s'", | |
1090 | hapd->conf->iface, MAC2STR(hapd->own_addr), | |
1091 | hapd->conf->ssid.ssid); | |
85141289 | 1092 | } |
6fc6879b JM |
1093 | |
1094 | if (hostapd_setup_wpa_psk(conf)) { | |
bb305cbd | 1095 | wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); |
6fc6879b JM |
1096 | return -1; |
1097 | } | |
1098 | ||
6fc6879b JM |
1099 | /* Set SSID for the kernel driver (to be used in beacon and probe |
1100 | * response frames) */ | |
1101 | if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid, | |
1102 | conf->ssid.ssid_len)) { | |
bb305cbd | 1103 | wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); |
6fc6879b JM |
1104 | return -1; |
1105 | } | |
1106 | ||
1107 | if (wpa_debug_level == MSG_MSGDUMP) | |
1108 | conf->radius->msg_dumps = 1; | |
74784010 | 1109 | #ifndef CONFIG_NO_RADIUS |
6fc6879b JM |
1110 | hapd->radius = radius_client_init(hapd, conf->radius); |
1111 | if (hapd->radius == NULL) { | |
bb305cbd | 1112 | wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); |
6fc6879b JM |
1113 | return -1; |
1114 | } | |
74784010 | 1115 | #endif /* CONFIG_NO_RADIUS */ |
6fc6879b JM |
1116 | |
1117 | if (hostapd_acl_init(hapd)) { | |
bb305cbd | 1118 | wpa_printf(MSG_ERROR, "ACL initialization failed."); |
6fc6879b JM |
1119 | return -1; |
1120 | } | |
ad08c363 JM |
1121 | if (hostapd_init_wps(hapd, conf)) |
1122 | return -1; | |
6fc6879b JM |
1123 | |
1124 | if (ieee802_1x_init(hapd)) { | |
bb305cbd | 1125 | wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); |
6fc6879b JM |
1126 | return -1; |
1127 | } | |
1128 | ||
1129 | if (hapd->conf->wpa && hostapd_setup_wpa(hapd)) | |
1130 | return -1; | |
1131 | ||
1132 | if (accounting_init(hapd)) { | |
bb305cbd | 1133 | wpa_printf(MSG_ERROR, "Accounting initialization failed."); |
6fc6879b JM |
1134 | return -1; |
1135 | } | |
1136 | ||
1137 | if (hapd->conf->ieee802_11f && | |
1138 | (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) { | |
bb305cbd JM |
1139 | wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " |
1140 | "failed."); | |
6fc6879b JM |
1141 | return -1; |
1142 | } | |
1143 | ||
1144 | if (hostapd_ctrl_iface_init(hapd)) { | |
bb305cbd | 1145 | wpa_printf(MSG_ERROR, "Failed to setup control interface"); |
6fc6879b JM |
1146 | return -1; |
1147 | } | |
1148 | ||
85141289 | 1149 | if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { |
bb305cbd | 1150 | wpa_printf(MSG_ERROR, "VLAN initialization failed."); |
6fc6879b JM |
1151 | return -1; |
1152 | } | |
1153 | ||
1154 | #ifdef CONFIG_IEEE80211R | |
85141289 JM |
1155 | if (!hostapd_drv_none(hapd)) { |
1156 | hapd->l2 = l2_packet_init(hapd->conf->iface, NULL, ETH_P_RRB, | |
1157 | hostapd_rrb_receive, hapd, 0); | |
1158 | if (hapd->l2 == NULL && | |
1159 | (hapd->driver == NULL || | |
1160 | hapd->driver->send_ether == NULL)) { | |
bb305cbd JM |
1161 | wpa_printf(MSG_ERROR, "Failed to open l2_packet " |
1162 | "interface"); | |
85141289 JM |
1163 | return -1; |
1164 | } | |
6fc6879b JM |
1165 | } |
1166 | #endif /* CONFIG_IEEE80211R */ | |
1167 | ||
1168 | ieee802_11_set_beacon(hapd); | |
1169 | ||
74784010 | 1170 | #ifdef RADIUS_SERVER |
6fc6879b JM |
1171 | if (conf->radius_server_clients && |
1172 | hostapd_setup_radius_srv(hapd, conf)) | |
1173 | return -1; | |
74784010 | 1174 | #endif /* RADIUS_SERVER */ |
6fc6879b JM |
1175 | |
1176 | return 0; | |
1177 | } | |
1178 | ||
1179 | ||
990ec378 JM |
1180 | static void hostapd_tx_queue_params(struct hostapd_iface *iface) |
1181 | { | |
1182 | struct hostapd_data *hapd = iface->bss[0]; | |
1183 | int i; | |
1184 | struct hostapd_tx_queue_params *p; | |
1185 | ||
1186 | for (i = 0; i < NUM_TX_QUEUES; i++) { | |
1187 | p = &iface->conf->tx_queue[i]; | |
1188 | ||
1189 | if (!p->configured) | |
1190 | continue; | |
1191 | ||
1192 | if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, | |
1193 | p->cwmax, p->burst)) { | |
bb305cbd JM |
1194 | wpa_printf(MSG_DEBUG, "Failed to set TX queue " |
1195 | "parameters for queue %d.", i); | |
990ec378 JM |
1196 | /* Continue anyway */ |
1197 | } | |
1198 | } | |
1199 | } | |
1200 | ||
1201 | ||
ddaa83eb | 1202 | static int setup_interface(struct hostapd_iface *iface) |
6fc6879b JM |
1203 | { |
1204 | struct hostapd_data *hapd = iface->bss[0]; | |
1205 | struct hostapd_bss_config *conf = hapd->conf; | |
1206 | size_t i; | |
1207 | char country[4]; | |
1208 | u8 *b = conf->bssid; | |
1209 | ||
1210 | /* | |
1211 | * Initialize the driver interface and make sure that all BSSes get | |
1212 | * configured with a pointer to this driver interface. | |
1213 | */ | |
92f475b4 JM |
1214 | if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) |
1215 | b = NULL; | |
1216 | hapd->drv_priv = hostapd_driver_init(hapd, b); | |
6fc6879b JM |
1217 | |
1218 | if (hapd->drv_priv == NULL) { | |
bb305cbd JM |
1219 | wpa_printf(MSG_ERROR, "%s driver initialization failed.", |
1220 | hapd->driver ? hapd->driver->name : "Unknown"); | |
6fc6879b JM |
1221 | hapd->driver = NULL; |
1222 | return -1; | |
1223 | } | |
1224 | for (i = 0; i < iface->num_bss; i++) { | |
1225 | iface->bss[i]->driver = hapd->driver; | |
1226 | iface->bss[i]->drv_priv = hapd->drv_priv; | |
1227 | } | |
1228 | ||
1229 | if (hostapd_validate_bssid_configuration(iface)) | |
1230 | return -1; | |
1231 | ||
6f4071c0 JM |
1232 | if (hapd->iconf->country[0] && hapd->iconf->country[1]) { |
1233 | os_memcpy(country, hapd->iconf->country, 3); | |
1234 | country[3] = '\0'; | |
1235 | if (hostapd_set_country(hapd, country) < 0) { | |
1236 | wpa_printf(MSG_ERROR, "Failed to set country code"); | |
1237 | return -1; | |
1238 | } | |
6fc6879b JM |
1239 | } |
1240 | ||
6fc6879b JM |
1241 | if (hostapd_get_hw_features(iface)) { |
1242 | /* Not all drivers support this yet, so continue without hw | |
1243 | * feature data. */ | |
1244 | } else { | |
ddaa83eb JM |
1245 | int ret = hostapd_select_hw_mode(iface); |
1246 | if (ret < 0) { | |
bb305cbd JM |
1247 | wpa_printf(MSG_ERROR, "Could not select hw_mode and " |
1248 | "channel. (%d)", ret); | |
ddaa83eb JM |
1249 | return -1; |
1250 | } | |
ad1e68e6 JM |
1251 | ret = hostapd_check_ht_capab(iface); |
1252 | if (ret < 0) | |
1253 | return -1; | |
1254 | if (ret == 1) { | |
1255 | wpa_printf(MSG_DEBUG, "Interface initialization will " | |
1256 | "be completed in a callback"); | |
1257 | return 0; | |
1258 | } | |
1259 | } | |
1260 | return hostapd_setup_interface_complete(iface, 0); | |
1261 | } | |
1262 | ||
1263 | ||
1264 | int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) | |
1265 | { | |
1266 | struct hostapd_data *hapd = iface->bss[0]; | |
1267 | int freq; | |
1268 | size_t j; | |
1269 | u8 *prev_addr; | |
1270 | ||
1271 | if (err) { | |
1272 | wpa_printf(MSG_ERROR, "Interface initialization failed"); | |
1273 | eloop_terminate(); | |
1274 | return -1; | |
6fc6879b JM |
1275 | } |
1276 | ||
ad1e68e6 | 1277 | wpa_printf(MSG_DEBUG, "Completing interface initialization"); |
ddaa83eb JM |
1278 | if (hapd->iconf->channel) { |
1279 | freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); | |
bb305cbd JM |
1280 | wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " |
1281 | "Frequency: %d MHz", | |
1282 | hostapd_hw_mode_txt(hapd->iconf->hw_mode), | |
1283 | hapd->iconf->channel, freq); | |
6fc6879b | 1284 | |
95da9bbc | 1285 | if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq, |
9c6d8e1d | 1286 | hapd->iconf->channel, |
fe0f58fa | 1287 | hapd->iconf->ieee80211n, |
95da9bbc | 1288 | hapd->iconf->secondary_channel)) { |
bb305cbd JM |
1289 | wpa_printf(MSG_ERROR, "Could not set channel for " |
1290 | "kernel driver"); | |
ddaa83eb JM |
1291 | return -1; |
1292 | } | |
1293 | } | |
6fc6879b | 1294 | |
ddaa83eb JM |
1295 | if (hapd->iconf->rts_threshold > -1 && |
1296 | hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { | |
bb305cbd JM |
1297 | wpa_printf(MSG_ERROR, "Could not set RTS threshold for " |
1298 | "kernel driver"); | |
ddaa83eb JM |
1299 | return -1; |
1300 | } | |
1301 | ||
1302 | if (hapd->iconf->fragm_threshold > -1 && | |
1303 | hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { | |
bb305cbd JM |
1304 | wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " |
1305 | "for kernel driver"); | |
ddaa83eb JM |
1306 | return -1; |
1307 | } | |
6fc6879b | 1308 | |
ddaa83eb JM |
1309 | prev_addr = hapd->own_addr; |
1310 | ||
1311 | for (j = 0; j < iface->num_bss; j++) { | |
1312 | hapd = iface->bss[j]; | |
1313 | if (j) | |
1314 | os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); | |
1315 | if (hostapd_setup_bss(hapd, j == 0)) | |
1316 | return -1; | |
1317 | if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) | |
1318 | prev_addr = hapd->own_addr; | |
1319 | } | |
1320 | ||
1321 | hostapd_tx_queue_params(iface); | |
1322 | ||
1323 | ap_list_init(iface); | |
1324 | ||
1325 | if (hostapd_driver_commit(hapd) < 0) { | |
1326 | wpa_printf(MSG_ERROR, "%s: Failed to commit driver " | |
1327 | "configuration", __func__); | |
1328 | return -1; | |
1329 | } | |
1330 | ||
ad1e68e6 JM |
1331 | wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", |
1332 | iface->bss[0]->conf->iface); | |
1333 | ||
21db94c5 | 1334 | return 0; |
6fc6879b JM |
1335 | } |
1336 | ||
1337 | ||
1338 | /** | |
ddaa83eb | 1339 | * hostapd_setup_interface - Setup of an interface |
6fc6879b | 1340 | * @iface: Pointer to interface data. |
ddaa83eb | 1341 | * Returns: 0 on success, -1 on failure |
6fc6879b JM |
1342 | * |
1343 | * Initializes the driver interface, validates the configuration, | |
1344 | * and sets driver parameters based on the configuration. | |
ddaa83eb | 1345 | * Flushes old stations, sets the channel, encryption, |
6fc6879b JM |
1346 | * beacons, and WDS links based on the configuration. |
1347 | */ | |
5c333467 | 1348 | int hostapd_setup_interface(struct hostapd_iface *iface) |
6fc6879b | 1349 | { |
ddaa83eb JM |
1350 | int ret; |
1351 | ||
1352 | ret = setup_interface(iface); | |
1353 | if (ret) { | |
1354 | wpa_printf(MSG_DEBUG, "%s: Unable to setup interface.", | |
6fc6879b | 1355 | iface->bss[0]->conf->iface); |
ddaa83eb | 1356 | eloop_terminate(); |
6fc6879b JM |
1357 | return -1; |
1358 | } | |
1359 | ||
6fc6879b JM |
1360 | return 0; |
1361 | } | |
1362 | ||
1363 | ||
6fc6879b JM |
1364 | /** |
1365 | * hostapd_alloc_bss_data - Allocate and initialize per-BSS data | |
1366 | * @hapd_iface: Pointer to interface data | |
1367 | * @conf: Pointer to per-interface configuration | |
1368 | * @bss: Pointer to per-BSS configuration for this BSS | |
1369 | * Returns: Pointer to allocated BSS data | |
1370 | * | |
1371 | * This function is used to allocate per-BSS data structure. This data will be | |
1372 | * freed after hostapd_cleanup() is called for it during interface | |
1373 | * deinitialization. | |
1374 | */ | |
b6a7859d | 1375 | struct hostapd_data * |
6fc6879b JM |
1376 | hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, |
1377 | struct hostapd_config *conf, | |
1378 | struct hostapd_bss_config *bss) | |
1379 | { | |
1380 | struct hostapd_data *hapd; | |
1381 | ||
1382 | hapd = os_zalloc(sizeof(*hapd)); | |
1383 | if (hapd == NULL) | |
1384 | return NULL; | |
1385 | ||
1386 | hapd->iconf = conf; | |
1387 | hapd->conf = bss; | |
1388 | hapd->iface = hapd_iface; | |
1389 | ||
6fc6879b JM |
1390 | #ifdef EAP_TLS_FUNCS |
1391 | if (hapd->conf->eap_server && | |
1392 | (hapd->conf->ca_cert || hapd->conf->server_cert || | |
1393 | hapd->conf->dh_file)) { | |
1394 | struct tls_connection_params params; | |
1395 | ||
1396 | hapd->ssl_ctx = tls_init(NULL); | |
1397 | if (hapd->ssl_ctx == NULL) { | |
bb305cbd | 1398 | wpa_printf(MSG_ERROR, "Failed to initialize TLS"); |
6fc6879b JM |
1399 | goto fail; |
1400 | } | |
1401 | ||
1402 | os_memset(¶ms, 0, sizeof(params)); | |
1403 | params.ca_cert = hapd->conf->ca_cert; | |
1404 | params.client_cert = hapd->conf->server_cert; | |
1405 | params.private_key = hapd->conf->private_key; | |
1406 | params.private_key_passwd = hapd->conf->private_key_passwd; | |
1407 | params.dh_file = hapd->conf->dh_file; | |
1408 | ||
1409 | if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) { | |
bb305cbd | 1410 | wpa_printf(MSG_ERROR, "Failed to set TLS parameters"); |
6fc6879b JM |
1411 | goto fail; |
1412 | } | |
1413 | ||
1414 | if (tls_global_set_verify(hapd->ssl_ctx, | |
1415 | hapd->conf->check_crl)) { | |
bb305cbd | 1416 | wpa_printf(MSG_ERROR, "Failed to enable check_crl"); |
6fc6879b JM |
1417 | goto fail; |
1418 | } | |
1419 | } | |
1420 | #endif /* EAP_TLS_FUNCS */ | |
1421 | ||
95272a88 | 1422 | #ifdef EAP_SIM_DB |
6fc6879b JM |
1423 | if (hapd->conf->eap_sim_db) { |
1424 | hapd->eap_sim_db_priv = | |
1425 | eap_sim_db_init(hapd->conf->eap_sim_db, | |
1426 | hostapd_sim_db_cb, hapd); | |
1427 | if (hapd->eap_sim_db_priv == NULL) { | |
bb305cbd JM |
1428 | wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM " |
1429 | "database interface"); | |
6fc6879b JM |
1430 | goto fail; |
1431 | } | |
1432 | } | |
95272a88 | 1433 | #endif /* EAP_SIM_DB */ |
6fc6879b | 1434 | |
6fc6879b JM |
1435 | hapd->driver = hapd->iconf->driver; |
1436 | ||
1437 | return hapd; | |
1438 | ||
95272a88 | 1439 | #if defined(EAP_TLS_FUNCS) || defined(EAP_SIM_DB) |
6fc6879b JM |
1440 | fail: |
1441 | #endif | |
1442 | /* TODO: cleanup allocated resources(?) */ | |
1443 | os_free(hapd); | |
1444 | return NULL; | |
1445 | } | |
1446 | ||
1447 | ||
5c333467 | 1448 | void hostapd_interface_deinit(struct hostapd_iface *iface) |
5fa30f32 JM |
1449 | { |
1450 | size_t j; | |
1451 | ||
1452 | if (iface == NULL) | |
1453 | return; | |
1454 | ||
1455 | hostapd_cleanup_iface_pre(iface); | |
1456 | for (j = 0; j < iface->num_bss; j++) { | |
1457 | struct hostapd_data *hapd = iface->bss[j]; | |
1458 | hostapd_free_stas(hapd); | |
1459 | hostapd_flush_old_stations(hapd); | |
1460 | hostapd_cleanup(hapd); | |
1461 | if (j == iface->num_bss - 1 && hapd->driver) | |
1462 | hostapd_driver_deinit(hapd); | |
1463 | } | |
1464 | for (j = 0; j < iface->num_bss; j++) | |
1465 | os_free(iface->bss[j]); | |
1466 | hostapd_cleanup_iface(iface); | |
1467 | } | |
fa16028d JM |
1468 | |
1469 | ||
1470 | int hostapd_register_probereq_cb(struct hostapd_data *hapd, | |
1471 | void (*cb)(void *ctx, const u8 *sa, | |
1472 | const u8 *ie, size_t ie_len), | |
1473 | void *ctx) | |
1474 | { | |
1475 | struct hostapd_probereq_cb *n; | |
1476 | ||
1477 | n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) * | |
1478 | sizeof(struct hostapd_probereq_cb)); | |
1479 | if (n == NULL) | |
1480 | return -1; | |
1481 | ||
1482 | hapd->probereq_cb = n; | |
1483 | n = &hapd->probereq_cb[hapd->num_probereq_cb]; | |
1484 | hapd->num_probereq_cb++; | |
1485 | ||
1486 | n->cb = cb; | |
1487 | n->ctx = ctx; | |
1488 | ||
1489 | return 0; | |
1490 | } | |
e3bd3912 JM |
1491 | |
1492 | ||
1493 | int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, | |
1494 | int enabled) | |
1495 | { | |
1496 | struct wpa_bss_params params; | |
1497 | os_memset(¶ms, 0, sizeof(params)); | |
1498 | params.ifname = ifname; | |
1499 | params.enabled = enabled; | |
1500 | return hostapd_set_ieee8021x(hapd, ¶ms); | |
1501 | } |