]>
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 | ||
6226e38d | 15 | #include "utils/includes.h" |
6fc6879b | 16 | |
6226e38d JM |
17 | #include "utils/common.h" |
18 | #include "utils/eloop.h" | |
03da66bd | 19 | #include "common/ieee802_11_defs.h" |
03da66bd | 20 | #include "radius/radius_client.h" |
6226e38d JM |
21 | #include "hostapd.h" |
22 | #include "authsrv.h" | |
23 | #include "sta_info.h" | |
24 | #include "accounting.h" | |
25 | #include "ap_list.h" | |
26 | #include "beacon.h" | |
27 | #include "iapp.h" | |
28 | #include "ieee802_1x.h" | |
29 | #include "ieee802_11_auth.h" | |
30 | #include "vlan_init.h" | |
31 | #include "wpa_auth.h" | |
32 | #include "wps_hostapd.h" | |
6fc6879b | 33 | #include "hw_features.h" |
bfddd95c | 34 | #include "driver_i.h" |
c442055e | 35 | #include "wpa_auth_glue.h" |
a4f21109 | 36 | #include "ap_drv_ops.h" |
6fc6879b JM |
37 | |
38 | ||
ad08c363 | 39 | static int hostapd_flush_old_stations(struct hostapd_data *hapd); |
ad08c363 | 40 | static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); |
6fc6879b | 41 | |
6fc6879b | 42 | extern int wpa_debug_level; |
6fc6879b | 43 | |
6fc6879b | 44 | |
ad08c363 JM |
45 | int hostapd_reload_config(struct hostapd_iface *iface) |
46 | { | |
47 | struct hostapd_data *hapd = iface->bss[0]; | |
48 | struct hostapd_config *newconf, *oldconf; | |
c213cc04 | 49 | size_t j; |
ad08c363 | 50 | |
41d719d6 JM |
51 | if (iface->config_read_cb == NULL) |
52 | return -1; | |
53 | newconf = iface->config_read_cb(iface->config_fname); | |
ad08c363 JM |
54 | if (newconf == NULL) |
55 | return -1; | |
56 | ||
57 | /* | |
58 | * Deauthenticate all stations since the new configuration may not | |
59 | * allow them to use the BSS anymore. | |
60 | */ | |
c213cc04 JM |
61 | for (j = 0; j < iface->num_bss; j++) |
62 | hostapd_flush_old_stations(iface->bss[j]); | |
ad08c363 | 63 | |
74784010 | 64 | #ifndef CONFIG_NO_RADIUS |
ad08c363 JM |
65 | /* TODO: update dynamic data based on changed configuration |
66 | * items (e.g., open/close sockets, etc.) */ | |
67 | radius_client_flush(hapd->radius, 0); | |
74784010 | 68 | #endif /* CONFIG_NO_RADIUS */ |
ad08c363 JM |
69 | |
70 | oldconf = hapd->iconf; | |
71 | hapd->iconf = newconf; | |
72 | hapd->conf = &newconf->bss[0]; | |
73 | iface->conf = newconf; | |
74 | ||
75 | if (hostapd_setup_wpa_psk(hapd->conf)) { | |
76 | wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " | |
77 | "after reloading configuration"); | |
78 | } | |
79 | ||
80 | if (hapd->conf->wpa && hapd->wpa_auth == NULL) | |
81 | hostapd_setup_wpa(hapd); | |
c442055e JM |
82 | else if (hapd->conf->wpa) |
83 | hostapd_reconfig_wpa(hapd); | |
84 | else if (hapd->wpa_auth) { | |
ad08c363 JM |
85 | wpa_deinit(hapd->wpa_auth); |
86 | hapd->wpa_auth = NULL; | |
87 | hostapd_set_privacy(hapd, 0); | |
88 | hostapd_setup_encryption(hapd->conf->iface, hapd); | |
89 | } | |
90 | ||
91 | ieee802_11_set_beacon(hapd); | |
92 | ||
c813b695 JM |
93 | if (hapd->conf->ssid.ssid_set && |
94 | hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, | |
95 | hapd->conf->ssid.ssid_len)) { | |
96 | wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); | |
97 | /* try to continue */ | |
98 | } | |
99 | ||
100 | if (hapd->conf->ieee802_1x || hapd->conf->wpa) | |
010401fe | 101 | hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1); |
e3bd3912 | 102 | else |
010401fe | 103 | hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0); |
c813b695 | 104 | |
ad08c363 JM |
105 | hostapd_config_free(oldconf); |
106 | ||
107 | wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | ||
6fc6879b JM |
113 | static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, |
114 | char *ifname) | |
115 | { | |
116 | int i; | |
117 | ||
118 | for (i = 0; i < NUM_WEP_KEYS; i++) { | |
45cefa0b JM |
119 | if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, |
120 | i == 0 ? 1 : 0, NULL, 0, NULL, 0)) { | |
bb305cbd JM |
121 | wpa_printf(MSG_DEBUG, "Failed to clear default " |
122 | "encryption keys (ifname=%s keyidx=%d)", | |
123 | ifname, i); | |
6fc6879b JM |
124 | } |
125 | } | |
1aa5c134 JM |
126 | #ifdef CONFIG_IEEE80211W |
127 | if (hapd->conf->ieee80211w) { | |
128 | for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { | |
45cefa0b JM |
129 | if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, |
130 | i, i == 0 ? 1 : 0, NULL, 0, | |
131 | NULL, 0)) { | |
bb305cbd JM |
132 | wpa_printf(MSG_DEBUG, "Failed to clear " |
133 | "default mgmt encryption keys " | |
134 | "(ifname=%s keyidx=%d)", ifname, i); | |
1aa5c134 JM |
135 | } |
136 | } | |
137 | } | |
138 | #endif /* CONFIG_IEEE80211W */ | |
6fc6879b JM |
139 | } |
140 | ||
141 | ||
142 | static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) | |
143 | { | |
144 | hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); | |
145 | return 0; | |
146 | } | |
147 | ||
148 | ||
149 | static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) | |
150 | { | |
151 | int errors = 0, idx; | |
152 | struct hostapd_ssid *ssid = &hapd->conf->ssid; | |
153 | ||
154 | idx = ssid->wep.idx; | |
155 | if (ssid->wep.default_len && | |
45cefa0b JM |
156 | hapd->drv.set_key(hapd->conf->iface, |
157 | hapd, WPA_ALG_WEP, NULL, idx, | |
158 | idx == ssid->wep.idx, | |
159 | NULL, 0, ssid->wep.key[idx], | |
160 | ssid->wep.len[idx])) { | |
bb305cbd | 161 | wpa_printf(MSG_WARNING, "Could not set WEP encryption."); |
6fc6879b JM |
162 | errors++; |
163 | } | |
164 | ||
165 | if (ssid->dyn_vlan_keys) { | |
166 | size_t i; | |
167 | for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) { | |
168 | const char *ifname; | |
169 | struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i]; | |
170 | if (key == NULL) | |
171 | continue; | |
172 | ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, | |
173 | i); | |
174 | if (ifname == NULL) | |
175 | continue; | |
176 | ||
177 | idx = key->idx; | |
45cefa0b JM |
178 | if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, |
179 | idx, idx == key->idx, NULL, 0, | |
180 | key->key[idx], key->len[idx])) { | |
bb305cbd JM |
181 | wpa_printf(MSG_WARNING, "Could not set " |
182 | "dynamic VLAN WEP encryption."); | |
6fc6879b JM |
183 | errors++; |
184 | } | |
185 | } | |
186 | } | |
187 | ||
188 | return errors; | |
189 | } | |
190 | ||
191 | /** | |
192 | * hostapd_cleanup - Per-BSS cleanup (deinitialization) | |
193 | * @hapd: Pointer to BSS data | |
194 | * | |
195 | * This function is used to free all per-BSS data structures and resources. | |
196 | * This gets called in a loop for each BSS between calls to | |
197 | * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface | |
198 | * is deinitialized. Most of the modules that are initialized in | |
199 | * hostapd_setup_bss() are deinitialized here. | |
200 | */ | |
201 | static void hostapd_cleanup(struct hostapd_data *hapd) | |
202 | { | |
70db2ab3 JM |
203 | if (hapd->iface->ctrl_iface_deinit) |
204 | hapd->iface->ctrl_iface_deinit(hapd); | |
6fc6879b | 205 | |
6fc6879b JM |
206 | iapp_deinit(hapd->iapp); |
207 | hapd->iapp = NULL; | |
208 | accounting_deinit(hapd); | |
c442055e | 209 | hostapd_deinit_wpa(hapd); |
6fc6879b JM |
210 | vlan_deinit(hapd); |
211 | hostapd_acl_deinit(hapd); | |
74784010 | 212 | #ifndef CONFIG_NO_RADIUS |
6fc6879b JM |
213 | radius_client_deinit(hapd->radius); |
214 | hapd->radius = NULL; | |
74784010 | 215 | #endif /* CONFIG_NO_RADIUS */ |
6fc6879b | 216 | |
ad08c363 JM |
217 | hostapd_deinit_wps(hapd); |
218 | ||
2586bc64 | 219 | authsrv_deinit(hapd); |
6fc6879b JM |
220 | |
221 | if (hapd->interface_added && | |
22a7c9d7 | 222 | hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { |
bb305cbd JM |
223 | wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", |
224 | hapd->conf->iface); | |
6fc6879b | 225 | } |
fa16028d JM |
226 | |
227 | os_free(hapd->probereq_cb); | |
228 | hapd->probereq_cb = NULL; | |
6fc6879b JM |
229 | } |
230 | ||
231 | ||
232 | /** | |
233 | * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup | |
234 | * @iface: Pointer to interface data | |
235 | * | |
236 | * This function is called before per-BSS data structures are deinitialized | |
237 | * with hostapd_cleanup(). | |
238 | */ | |
239 | static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface) | |
240 | { | |
241 | } | |
242 | ||
243 | ||
244 | /** | |
245 | * hostapd_cleanup_iface - Complete per-interface cleanup | |
246 | * @iface: Pointer to interface data | |
247 | * | |
248 | * This function is called after per-BSS data structures are deinitialized | |
249 | * with hostapd_cleanup(). | |
250 | */ | |
251 | static void hostapd_cleanup_iface(struct hostapd_iface *iface) | |
252 | { | |
253 | hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); | |
254 | iface->hw_features = NULL; | |
255 | os_free(iface->current_rates); | |
256 | iface->current_rates = NULL; | |
257 | ap_list_deinit(iface); | |
258 | hostapd_config_free(iface->conf); | |
259 | iface->conf = NULL; | |
260 | ||
261 | os_free(iface->config_fname); | |
262 | os_free(iface->bss); | |
263 | os_free(iface); | |
264 | } | |
265 | ||
266 | ||
267 | static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) | |
268 | { | |
269 | int i; | |
270 | ||
271 | hostapd_broadcast_wep_set(hapd); | |
272 | ||
579bc0e6 JM |
273 | if (hapd->conf->ssid.wep.default_len) { |
274 | hostapd_set_privacy(hapd, 1); | |
6fc6879b | 275 | return 0; |
579bc0e6 | 276 | } |
6fc6879b JM |
277 | |
278 | for (i = 0; i < 4; i++) { | |
279 | if (hapd->conf->ssid.wep.key[i] && | |
45cefa0b JM |
280 | hapd->drv.set_key(iface, hapd, WPA_ALG_WEP, NULL, i, |
281 | i == hapd->conf->ssid.wep.idx, NULL, 0, | |
282 | hapd->conf->ssid.wep.key[i], | |
283 | hapd->conf->ssid.wep.len[i])) { | |
bb305cbd JM |
284 | wpa_printf(MSG_WARNING, "Could not set WEP " |
285 | "encryption."); | |
6fc6879b JM |
286 | return -1; |
287 | } | |
288 | if (hapd->conf->ssid.wep.key[i] && | |
289 | i == hapd->conf->ssid.wep.idx) | |
290 | hostapd_set_privacy(hapd, 1); | |
291 | } | |
292 | ||
293 | return 0; | |
294 | } | |
295 | ||
296 | ||
297 | static int hostapd_flush_old_stations(struct hostapd_data *hapd) | |
298 | { | |
299 | int ret = 0; | |
300 | ||
85141289 JM |
301 | if (hostapd_drv_none(hapd)) |
302 | return 0; | |
303 | ||
6fc6879b JM |
304 | wpa_printf(MSG_DEBUG, "Flushing old station entries"); |
305 | if (hostapd_flush(hapd)) { | |
bb305cbd | 306 | wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); |
6fc6879b JM |
307 | ret = -1; |
308 | } | |
309 | wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); | |
9302c5e1 JM |
310 | |
311 | /* New Prism2.5/3 STA firmware versions seem to have issues with this | |
312 | * broadcast deauth frame. This gets the firmware in odd state where | |
313 | * nothing works correctly, so let's skip sending this for the hostap | |
314 | * driver. */ | |
315 | if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) { | |
316 | u8 addr[ETH_ALEN]; | |
317 | os_memset(addr, 0xff, ETH_ALEN); | |
bdee6fce JM |
318 | hapd->drv.sta_deauth(hapd, addr, |
319 | WLAN_REASON_PREV_AUTH_NOT_VALID); | |
9302c5e1 | 320 | } |
6fc6879b JM |
321 | |
322 | return ret; | |
323 | } | |
324 | ||
325 | ||
6fc6879b JM |
326 | /** |
327 | * hostapd_validate_bssid_configuration - Validate BSSID configuration | |
328 | * @iface: Pointer to interface data | |
329 | * Returns: 0 on success, -1 on failure | |
330 | * | |
331 | * This function is used to validate that the configured BSSIDs are valid. | |
332 | */ | |
333 | static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) | |
334 | { | |
335 | u8 mask[ETH_ALEN] = { 0 }; | |
336 | struct hostapd_data *hapd = iface->bss[0]; | |
337 | unsigned int i = iface->conf->num_bss, bits = 0, j; | |
338 | int res; | |
90ac1f9f | 339 | int auto_addr = 0; |
6fc6879b | 340 | |
85141289 JM |
341 | if (hostapd_drv_none(hapd)) |
342 | return 0; | |
343 | ||
6fc6879b JM |
344 | /* Generate BSSID mask that is large enough to cover the BSSIDs. */ |
345 | ||
346 | /* Determine the bits necessary to cover the number of BSSIDs. */ | |
347 | for (i--; i; i >>= 1) | |
348 | bits++; | |
349 | ||
350 | /* Determine the bits necessary to any configured BSSIDs, | |
351 | if they are higher than the number of BSSIDs. */ | |
352 | for (j = 0; j < iface->conf->num_bss; j++) { | |
90ac1f9f JM |
353 | if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) { |
354 | if (j) | |
355 | auto_addr++; | |
6fc6879b | 356 | continue; |
90ac1f9f | 357 | } |
6fc6879b JM |
358 | |
359 | for (i = 0; i < ETH_ALEN; i++) { | |
360 | mask[i] |= | |
361 | iface->conf->bss[j].bssid[i] ^ | |
362 | hapd->own_addr[i]; | |
363 | } | |
364 | } | |
365 | ||
90ac1f9f JM |
366 | if (!auto_addr) |
367 | goto skip_mask_ext; | |
368 | ||
6fc6879b JM |
369 | for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) |
370 | ; | |
371 | j = 0; | |
372 | if (i < ETH_ALEN) { | |
373 | j = (5 - i) * 8; | |
374 | ||
375 | while (mask[i] != 0) { | |
376 | mask[i] >>= 1; | |
377 | j++; | |
378 | } | |
379 | } | |
380 | ||
381 | if (bits < j) | |
382 | bits = j; | |
383 | ||
90ac1f9f JM |
384 | if (bits > 40) { |
385 | wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", | |
386 | bits); | |
6fc6879b | 387 | return -1; |
90ac1f9f | 388 | } |
6fc6879b JM |
389 | |
390 | os_memset(mask, 0xff, ETH_ALEN); | |
391 | j = bits / 8; | |
392 | for (i = 5; i > 5 - j; i--) | |
393 | mask[i] = 0; | |
394 | j = bits % 8; | |
395 | while (j--) | |
396 | mask[i] <<= 1; | |
397 | ||
90ac1f9f | 398 | skip_mask_ext: |
6fc6879b JM |
399 | wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", |
400 | (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); | |
401 | ||
402 | res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); | |
403 | if (res == 0) | |
404 | return 0; | |
405 | ||
406 | if (res < 0) { | |
bb305cbd JM |
407 | wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " |
408 | MACSTR " for start address " MACSTR ".", | |
409 | MAC2STR(mask), MAC2STR(hapd->own_addr)); | |
6fc6879b JM |
410 | return -1; |
411 | } | |
412 | ||
90ac1f9f JM |
413 | if (!auto_addr) |
414 | return 0; | |
415 | ||
6fc6879b JM |
416 | for (i = 0; i < ETH_ALEN; i++) { |
417 | if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { | |
bb305cbd JM |
418 | wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR |
419 | " for start address " MACSTR ".", | |
420 | MAC2STR(mask), MAC2STR(hapd->own_addr)); | |
421 | wpa_printf(MSG_ERROR, "Start address must be the " | |
422 | "first address in the block (i.e., addr " | |
423 | "AND mask == addr)."); | |
6fc6879b JM |
424 | return -1; |
425 | } | |
426 | } | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
431 | ||
432 | static int mac_in_conf(struct hostapd_config *conf, const void *a) | |
433 | { | |
434 | size_t i; | |
435 | ||
436 | for (i = 0; i < conf->num_bss; i++) { | |
437 | if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) { | |
438 | return 1; | |
439 | } | |
440 | } | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | ||
6fc6879b JM |
446 | |
447 | ||
6fc6879b JM |
448 | /** |
449 | * hostapd_setup_bss - Per-BSS setup (initialization) | |
450 | * @hapd: Pointer to BSS data | |
451 | * @first: Whether this BSS is the first BSS of an interface | |
452 | * | |
453 | * This function is used to initialize all per-BSS data structures and | |
454 | * resources. This gets called in a loop for each BSS when an interface is | |
455 | * initialized. Most of the modules that are initialized here will be | |
456 | * deinitialized in hostapd_cleanup(). | |
457 | */ | |
458 | static int hostapd_setup_bss(struct hostapd_data *hapd, int first) | |
459 | { | |
460 | struct hostapd_bss_config *conf = hapd->conf; | |
461 | u8 ssid[HOSTAPD_MAX_SSID_LEN + 1]; | |
462 | int ssid_len, set_ssid; | |
463 | ||
464 | if (!first) { | |
465 | if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) { | |
466 | /* Allocate the next available BSSID. */ | |
467 | do { | |
468 | inc_byte_array(hapd->own_addr, ETH_ALEN); | |
469 | } while (mac_in_conf(hapd->iconf, hapd->own_addr)); | |
470 | } else { | |
471 | /* Allocate the configured BSSID. */ | |
472 | os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); | |
473 | ||
474 | if (hostapd_mac_comp(hapd->own_addr, | |
475 | hapd->iface->bss[0]->own_addr) == | |
476 | 0) { | |
bb305cbd JM |
477 | wpa_printf(MSG_ERROR, "BSS '%s' may not have " |
478 | "BSSID set to the MAC address of " | |
479 | "the radio", hapd->conf->iface); | |
6fc6879b JM |
480 | return -1; |
481 | } | |
482 | } | |
483 | ||
484 | hapd->interface_added = 1; | |
22a7c9d7 | 485 | if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, |
8043e725 | 486 | hapd->conf->iface, hapd->own_addr, hapd)) { |
bb305cbd JM |
487 | wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" |
488 | MACSTR ")", MAC2STR(hapd->own_addr)); | |
6fc6879b JM |
489 | return -1; |
490 | } | |
491 | } | |
492 | ||
c213cc04 JM |
493 | hostapd_flush_old_stations(hapd); |
494 | hostapd_set_privacy(hapd, 0); | |
495 | ||
496 | hostapd_broadcast_wep_clear(hapd); | |
497 | if (hostapd_setup_encryption(hapd->conf->iface, hapd)) | |
498 | return -1; | |
499 | ||
6fc6879b JM |
500 | /* |
501 | * Fetch the SSID from the system and use it or, | |
502 | * if one was specified in the config file, verify they | |
503 | * match. | |
504 | */ | |
505 | ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); | |
506 | if (ssid_len < 0) { | |
bb305cbd | 507 | wpa_printf(MSG_ERROR, "Could not read SSID from system"); |
6fc6879b JM |
508 | return -1; |
509 | } | |
510 | if (conf->ssid.ssid_set) { | |
511 | /* | |
512 | * If SSID is specified in the config file and it differs | |
513 | * from what is being used then force installation of the | |
514 | * new SSID. | |
515 | */ | |
516 | set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || | |
517 | os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); | |
518 | } else { | |
519 | /* | |
520 | * No SSID in the config file; just use the one we got | |
521 | * from the system. | |
522 | */ | |
523 | set_ssid = 0; | |
524 | conf->ssid.ssid_len = ssid_len; | |
525 | os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); | |
526 | conf->ssid.ssid[conf->ssid.ssid_len] = '\0'; | |
527 | } | |
528 | ||
85141289 | 529 | if (!hostapd_drv_none(hapd)) { |
bb305cbd JM |
530 | wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR |
531 | " and ssid '%s'", | |
532 | hapd->conf->iface, MAC2STR(hapd->own_addr), | |
533 | hapd->conf->ssid.ssid); | |
85141289 | 534 | } |
6fc6879b JM |
535 | |
536 | if (hostapd_setup_wpa_psk(conf)) { | |
bb305cbd | 537 | wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); |
6fc6879b JM |
538 | return -1; |
539 | } | |
540 | ||
6fc6879b JM |
541 | /* Set SSID for the kernel driver (to be used in beacon and probe |
542 | * response frames) */ | |
543 | if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid, | |
544 | conf->ssid.ssid_len)) { | |
bb305cbd | 545 | wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); |
6fc6879b JM |
546 | return -1; |
547 | } | |
548 | ||
549 | if (wpa_debug_level == MSG_MSGDUMP) | |
550 | conf->radius->msg_dumps = 1; | |
74784010 | 551 | #ifndef CONFIG_NO_RADIUS |
6fc6879b JM |
552 | hapd->radius = radius_client_init(hapd, conf->radius); |
553 | if (hapd->radius == NULL) { | |
bb305cbd | 554 | wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); |
6fc6879b JM |
555 | return -1; |
556 | } | |
74784010 | 557 | #endif /* CONFIG_NO_RADIUS */ |
6fc6879b JM |
558 | |
559 | if (hostapd_acl_init(hapd)) { | |
bb305cbd | 560 | wpa_printf(MSG_ERROR, "ACL initialization failed."); |
6fc6879b JM |
561 | return -1; |
562 | } | |
ad08c363 JM |
563 | if (hostapd_init_wps(hapd, conf)) |
564 | return -1; | |
6fc6879b JM |
565 | |
566 | if (ieee802_1x_init(hapd)) { | |
bb305cbd | 567 | wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); |
6fc6879b JM |
568 | return -1; |
569 | } | |
570 | ||
571 | if (hapd->conf->wpa && hostapd_setup_wpa(hapd)) | |
572 | return -1; | |
573 | ||
574 | if (accounting_init(hapd)) { | |
bb305cbd | 575 | wpa_printf(MSG_ERROR, "Accounting initialization failed."); |
6fc6879b JM |
576 | return -1; |
577 | } | |
578 | ||
579 | if (hapd->conf->ieee802_11f && | |
580 | (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) { | |
bb305cbd JM |
581 | wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " |
582 | "failed."); | |
6fc6879b JM |
583 | return -1; |
584 | } | |
585 | ||
70db2ab3 JM |
586 | if (hapd->iface->ctrl_iface_init && |
587 | hapd->iface->ctrl_iface_init(hapd)) { | |
bb305cbd | 588 | wpa_printf(MSG_ERROR, "Failed to setup control interface"); |
6fc6879b JM |
589 | return -1; |
590 | } | |
591 | ||
85141289 | 592 | if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { |
bb305cbd | 593 | wpa_printf(MSG_ERROR, "VLAN initialization failed."); |
6fc6879b JM |
594 | return -1; |
595 | } | |
596 | ||
6fc6879b JM |
597 | ieee802_11_set_beacon(hapd); |
598 | ||
2586bc64 | 599 | if (authsrv_init(hapd) < 0) |
6fc6879b JM |
600 | return -1; |
601 | ||
602 | return 0; | |
603 | } | |
604 | ||
605 | ||
990ec378 JM |
606 | static void hostapd_tx_queue_params(struct hostapd_iface *iface) |
607 | { | |
608 | struct hostapd_data *hapd = iface->bss[0]; | |
609 | int i; | |
610 | struct hostapd_tx_queue_params *p; | |
611 | ||
612 | for (i = 0; i < NUM_TX_QUEUES; i++) { | |
613 | p = &iface->conf->tx_queue[i]; | |
614 | ||
615 | if (!p->configured) | |
616 | continue; | |
617 | ||
618 | if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, | |
619 | p->cwmax, p->burst)) { | |
bb305cbd JM |
620 | wpa_printf(MSG_DEBUG, "Failed to set TX queue " |
621 | "parameters for queue %d.", i); | |
990ec378 JM |
622 | /* Continue anyway */ |
623 | } | |
624 | } | |
625 | } | |
626 | ||
627 | ||
ddaa83eb | 628 | static int setup_interface(struct hostapd_iface *iface) |
6fc6879b JM |
629 | { |
630 | struct hostapd_data *hapd = iface->bss[0]; | |
6fc6879b JM |
631 | size_t i; |
632 | char country[4]; | |
6fc6879b JM |
633 | |
634 | /* | |
e5f2b59c JM |
635 | * Make sure that all BSSes get configured with a pointer to the same |
636 | * driver interface. | |
6fc6879b | 637 | */ |
e5f2b59c | 638 | for (i = 1; i < iface->num_bss; i++) { |
6fc6879b JM |
639 | iface->bss[i]->driver = hapd->driver; |
640 | iface->bss[i]->drv_priv = hapd->drv_priv; | |
641 | } | |
642 | ||
643 | if (hostapd_validate_bssid_configuration(iface)) | |
644 | return -1; | |
645 | ||
6f4071c0 JM |
646 | if (hapd->iconf->country[0] && hapd->iconf->country[1]) { |
647 | os_memcpy(country, hapd->iconf->country, 3); | |
648 | country[3] = '\0'; | |
649 | if (hostapd_set_country(hapd, country) < 0) { | |
650 | wpa_printf(MSG_ERROR, "Failed to set country code"); | |
651 | return -1; | |
652 | } | |
6fc6879b JM |
653 | } |
654 | ||
6fc6879b JM |
655 | if (hostapd_get_hw_features(iface)) { |
656 | /* Not all drivers support this yet, so continue without hw | |
657 | * feature data. */ | |
658 | } else { | |
ddaa83eb JM |
659 | int ret = hostapd_select_hw_mode(iface); |
660 | if (ret < 0) { | |
bb305cbd JM |
661 | wpa_printf(MSG_ERROR, "Could not select hw_mode and " |
662 | "channel. (%d)", ret); | |
ddaa83eb JM |
663 | return -1; |
664 | } | |
ad1e68e6 JM |
665 | ret = hostapd_check_ht_capab(iface); |
666 | if (ret < 0) | |
667 | return -1; | |
668 | if (ret == 1) { | |
669 | wpa_printf(MSG_DEBUG, "Interface initialization will " | |
670 | "be completed in a callback"); | |
671 | return 0; | |
672 | } | |
673 | } | |
674 | return hostapd_setup_interface_complete(iface, 0); | |
675 | } | |
676 | ||
677 | ||
678 | int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) | |
679 | { | |
680 | struct hostapd_data *hapd = iface->bss[0]; | |
681 | int freq; | |
682 | size_t j; | |
683 | u8 *prev_addr; | |
684 | ||
685 | if (err) { | |
686 | wpa_printf(MSG_ERROR, "Interface initialization failed"); | |
687 | eloop_terminate(); | |
688 | return -1; | |
6fc6879b JM |
689 | } |
690 | ||
ad1e68e6 | 691 | wpa_printf(MSG_DEBUG, "Completing interface initialization"); |
ddaa83eb JM |
692 | if (hapd->iconf->channel) { |
693 | freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); | |
bb305cbd JM |
694 | wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " |
695 | "Frequency: %d MHz", | |
696 | hostapd_hw_mode_txt(hapd->iconf->hw_mode), | |
697 | hapd->iconf->channel, freq); | |
6fc6879b | 698 | |
95da9bbc | 699 | if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq, |
9c6d8e1d | 700 | hapd->iconf->channel, |
fe0f58fa | 701 | hapd->iconf->ieee80211n, |
95da9bbc | 702 | hapd->iconf->secondary_channel)) { |
bb305cbd JM |
703 | wpa_printf(MSG_ERROR, "Could not set channel for " |
704 | "kernel driver"); | |
ddaa83eb JM |
705 | return -1; |
706 | } | |
707 | } | |
6fc6879b | 708 | |
ddaa83eb JM |
709 | if (hapd->iconf->rts_threshold > -1 && |
710 | hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { | |
bb305cbd JM |
711 | wpa_printf(MSG_ERROR, "Could not set RTS threshold for " |
712 | "kernel driver"); | |
ddaa83eb JM |
713 | return -1; |
714 | } | |
715 | ||
716 | if (hapd->iconf->fragm_threshold > -1 && | |
717 | hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { | |
bb305cbd JM |
718 | wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " |
719 | "for kernel driver"); | |
ddaa83eb JM |
720 | return -1; |
721 | } | |
6fc6879b | 722 | |
ddaa83eb JM |
723 | prev_addr = hapd->own_addr; |
724 | ||
725 | for (j = 0; j < iface->num_bss; j++) { | |
726 | hapd = iface->bss[j]; | |
727 | if (j) | |
728 | os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); | |
729 | if (hostapd_setup_bss(hapd, j == 0)) | |
730 | return -1; | |
731 | if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) | |
732 | prev_addr = hapd->own_addr; | |
733 | } | |
734 | ||
735 | hostapd_tx_queue_params(iface); | |
736 | ||
737 | ap_list_init(iface); | |
738 | ||
739 | if (hostapd_driver_commit(hapd) < 0) { | |
740 | wpa_printf(MSG_ERROR, "%s: Failed to commit driver " | |
741 | "configuration", __func__); | |
742 | return -1; | |
743 | } | |
744 | ||
ad1e68e6 JM |
745 | wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", |
746 | iface->bss[0]->conf->iface); | |
747 | ||
21db94c5 | 748 | return 0; |
6fc6879b JM |
749 | } |
750 | ||
751 | ||
752 | /** | |
ddaa83eb | 753 | * hostapd_setup_interface - Setup of an interface |
6fc6879b | 754 | * @iface: Pointer to interface data. |
ddaa83eb | 755 | * Returns: 0 on success, -1 on failure |
6fc6879b JM |
756 | * |
757 | * Initializes the driver interface, validates the configuration, | |
758 | * and sets driver parameters based on the configuration. | |
ddaa83eb | 759 | * Flushes old stations, sets the channel, encryption, |
6fc6879b JM |
760 | * beacons, and WDS links based on the configuration. |
761 | */ | |
5c333467 | 762 | int hostapd_setup_interface(struct hostapd_iface *iface) |
6fc6879b | 763 | { |
ddaa83eb JM |
764 | int ret; |
765 | ||
766 | ret = setup_interface(iface); | |
767 | if (ret) { | |
bee07ce8 | 768 | wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", |
6fc6879b JM |
769 | iface->bss[0]->conf->iface); |
770 | return -1; | |
771 | } | |
772 | ||
6fc6879b JM |
773 | return 0; |
774 | } | |
775 | ||
776 | ||
6fc6879b JM |
777 | /** |
778 | * hostapd_alloc_bss_data - Allocate and initialize per-BSS data | |
779 | * @hapd_iface: Pointer to interface data | |
780 | * @conf: Pointer to per-interface configuration | |
781 | * @bss: Pointer to per-BSS configuration for this BSS | |
782 | * Returns: Pointer to allocated BSS data | |
783 | * | |
784 | * This function is used to allocate per-BSS data structure. This data will be | |
785 | * freed after hostapd_cleanup() is called for it during interface | |
786 | * deinitialization. | |
787 | */ | |
b6a7859d | 788 | struct hostapd_data * |
6fc6879b JM |
789 | hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, |
790 | struct hostapd_config *conf, | |
791 | struct hostapd_bss_config *bss) | |
792 | { | |
793 | struct hostapd_data *hapd; | |
794 | ||
795 | hapd = os_zalloc(sizeof(*hapd)); | |
796 | if (hapd == NULL) | |
797 | return NULL; | |
798 | ||
bf65bc63 | 799 | hostapd_set_driver_ops(&hapd->drv); |
d24df7c3 | 800 | hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; |
6fc6879b JM |
801 | hapd->iconf = conf; |
802 | hapd->conf = bss; | |
803 | hapd->iface = hapd_iface; | |
6fc6879b JM |
804 | hapd->driver = hapd->iconf->driver; |
805 | ||
806 | return hapd; | |
6fc6879b JM |
807 | } |
808 | ||
809 | ||
5c333467 | 810 | void hostapd_interface_deinit(struct hostapd_iface *iface) |
5fa30f32 JM |
811 | { |
812 | size_t j; | |
813 | ||
814 | if (iface == NULL) | |
815 | return; | |
816 | ||
817 | hostapd_cleanup_iface_pre(iface); | |
818 | for (j = 0; j < iface->num_bss; j++) { | |
819 | struct hostapd_data *hapd = iface->bss[j]; | |
820 | hostapd_free_stas(hapd); | |
821 | hostapd_flush_old_stations(hapd); | |
822 | hostapd_cleanup(hapd); | |
5fa30f32 JM |
823 | } |
824 | for (j = 0; j < iface->num_bss; j++) | |
825 | os_free(iface->bss[j]); | |
826 | hostapd_cleanup_iface(iface); | |
827 | } | |
fa16028d JM |
828 | |
829 | ||
a2de634d JM |
830 | /** |
831 | * hostapd_new_assoc_sta - Notify that a new station associated with the AP | |
832 | * @hapd: Pointer to BSS data | |
833 | * @sta: Pointer to the associated STA data | |
834 | * @reassoc: 1 to indicate this was a re-association; 0 = first association | |
835 | * | |
836 | * This function will be called whenever a station associates with the AP. It | |
837 | * can be called from ieee802_11.c for drivers that export MLME to hostapd and | |
838 | * from drv_callbacks.c based on driver events for drivers that take care of | |
839 | * management frames (IEEE 802.11 authentication and association) internally. | |
840 | */ | |
841 | void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, | |
842 | int reassoc) | |
843 | { | |
844 | if (hapd->tkip_countermeasures) { | |
bdee6fce JM |
845 | hapd->drv.sta_deauth(hapd, sta->addr, |
846 | WLAN_REASON_MICHAEL_MIC_FAILURE); | |
a2de634d JM |
847 | return; |
848 | } | |
849 | ||
0aef3ec8 | 850 | hostapd_prune_associations(hapd, sta->addr); |
a2de634d JM |
851 | |
852 | /* IEEE 802.11F (IAPP) */ | |
853 | if (hapd->conf->ieee802_11f) | |
854 | iapp_new_station(hapd->iapp, sta); | |
855 | ||
856 | /* Start accounting here, if IEEE 802.1X and WPA are not used. | |
857 | * IEEE 802.1X/WPA code will start accounting after the station has | |
858 | * been authorized. */ | |
859 | if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) | |
860 | accounting_sta_start(hapd, sta); | |
861 | ||
862 | /* Start IEEE 802.1X authentication process for new stations */ | |
863 | ieee802_1x_new_station(hapd, sta); | |
864 | if (reassoc) { | |
865 | if (sta->auth_alg != WLAN_AUTH_FT && | |
866 | !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) | |
867 | wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); | |
868 | } else | |
869 | wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); | |
870 | } |