]>
Commit | Line | Data |
---|---|---|
5c333467 JM |
1 | /* |
2 | * hostapd / main() | |
9e074973 | 3 | * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> |
5c333467 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" |
5c333467 JM |
16 | #ifndef CONFIG_NATIVE_WINDOWS |
17 | #include <syslog.h> | |
18 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
19 | ||
6226e38d JM |
20 | #include "utils/common.h" |
21 | #include "utils/eloop.h" | |
d47fa330 | 22 | #include "crypto/random.h" |
03da66bd | 23 | #include "crypto/tls.h" |
90973fb2 | 24 | #include "common/version.h" |
e5f2b59c | 25 | #include "drivers/driver.h" |
5c333467 JM |
26 | #include "eap_server/eap.h" |
27 | #include "eap_server/tncs.h" | |
1057d78e | 28 | #include "ap/hostapd.h" |
6226e38d | 29 | #include "ap/ap_config.h" |
41d719d6 | 30 | #include "config_file.h" |
a4f21109 JM |
31 | #include "eap_register.h" |
32 | #include "dump_state.h" | |
70db2ab3 | 33 | #include "ctrl_iface.h" |
5c333467 JM |
34 | |
35 | ||
36 | extern int wpa_debug_level; | |
37 | extern int wpa_debug_show_keys; | |
38 | extern int wpa_debug_timestamp; | |
39 | ||
4b24282a JM |
40 | extern struct wpa_driver_ops *wpa_drivers[]; |
41 | ||
42 | ||
43 | struct hapd_global { | |
44 | void **drv_priv; | |
45 | size_t drv_count; | |
46 | }; | |
47 | ||
48 | static struct hapd_global global; | |
49 | ||
5c333467 JM |
50 | |
51 | struct hapd_interfaces { | |
52 | size_t count; | |
53 | struct hostapd_iface **iface; | |
54 | }; | |
55 | ||
56 | ||
1b56c26c JM |
57 | static int hostapd_for_each_interface(struct hapd_interfaces *interfaces, |
58 | int (*cb)(struct hostapd_iface *iface, | |
59 | void *ctx), void *ctx) | |
5c333467 | 60 | { |
5c333467 JM |
61 | size_t i; |
62 | int ret; | |
63 | ||
64 | for (i = 0; i < interfaces->count; i++) { | |
65 | ret = cb(interfaces->iface[i], ctx); | |
66 | if (ret) | |
67 | return ret; | |
68 | } | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | ||
74 | #ifndef CONFIG_NO_HOSTAPD_LOGGER | |
75 | static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, | |
76 | int level, const char *txt, size_t len) | |
77 | { | |
78 | struct hostapd_data *hapd = ctx; | |
79 | char *format, *module_str; | |
80 | int maxlen; | |
81 | int conf_syslog_level, conf_stdout_level; | |
82 | unsigned int conf_syslog, conf_stdout; | |
83 | ||
84 | maxlen = len + 100; | |
85 | format = os_malloc(maxlen); | |
86 | if (!format) | |
87 | return; | |
88 | ||
89 | if (hapd && hapd->conf) { | |
90 | conf_syslog_level = hapd->conf->logger_syslog_level; | |
91 | conf_stdout_level = hapd->conf->logger_stdout_level; | |
92 | conf_syslog = hapd->conf->logger_syslog; | |
93 | conf_stdout = hapd->conf->logger_stdout; | |
94 | } else { | |
95 | conf_syslog_level = conf_stdout_level = 0; | |
96 | conf_syslog = conf_stdout = (unsigned int) -1; | |
97 | } | |
98 | ||
99 | switch (module) { | |
100 | case HOSTAPD_MODULE_IEEE80211: | |
101 | module_str = "IEEE 802.11"; | |
102 | break; | |
103 | case HOSTAPD_MODULE_IEEE8021X: | |
104 | module_str = "IEEE 802.1X"; | |
105 | break; | |
106 | case HOSTAPD_MODULE_RADIUS: | |
107 | module_str = "RADIUS"; | |
108 | break; | |
109 | case HOSTAPD_MODULE_WPA: | |
110 | module_str = "WPA"; | |
111 | break; | |
112 | case HOSTAPD_MODULE_DRIVER: | |
113 | module_str = "DRIVER"; | |
114 | break; | |
115 | case HOSTAPD_MODULE_IAPP: | |
116 | module_str = "IAPP"; | |
117 | break; | |
118 | case HOSTAPD_MODULE_MLME: | |
119 | module_str = "MLME"; | |
120 | break; | |
121 | default: | |
122 | module_str = NULL; | |
123 | break; | |
124 | } | |
125 | ||
126 | if (hapd && hapd->conf && addr) | |
127 | os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", | |
128 | hapd->conf->iface, MAC2STR(addr), | |
129 | module_str ? " " : "", module_str, txt); | |
130 | else if (hapd && hapd->conf) | |
131 | os_snprintf(format, maxlen, "%s:%s%s %s", | |
132 | hapd->conf->iface, module_str ? " " : "", | |
133 | module_str, txt); | |
134 | else if (addr) | |
135 | os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", | |
136 | MAC2STR(addr), module_str ? " " : "", | |
137 | module_str, txt); | |
138 | else | |
139 | os_snprintf(format, maxlen, "%s%s%s", | |
140 | module_str, module_str ? ": " : "", txt); | |
141 | ||
142 | if ((conf_stdout & module) && level >= conf_stdout_level) { | |
143 | wpa_debug_print_timestamp(); | |
144 | printf("%s\n", format); | |
145 | } | |
146 | ||
147 | #ifndef CONFIG_NATIVE_WINDOWS | |
148 | if ((conf_syslog & module) && level >= conf_syslog_level) { | |
149 | int priority; | |
150 | switch (level) { | |
151 | case HOSTAPD_LEVEL_DEBUG_VERBOSE: | |
152 | case HOSTAPD_LEVEL_DEBUG: | |
153 | priority = LOG_DEBUG; | |
154 | break; | |
155 | case HOSTAPD_LEVEL_INFO: | |
156 | priority = LOG_INFO; | |
157 | break; | |
158 | case HOSTAPD_LEVEL_NOTICE: | |
159 | priority = LOG_NOTICE; | |
160 | break; | |
161 | case HOSTAPD_LEVEL_WARNING: | |
162 | priority = LOG_WARNING; | |
163 | break; | |
164 | default: | |
165 | priority = LOG_INFO; | |
166 | break; | |
167 | } | |
168 | syslog(priority, "%s", format); | |
169 | } | |
170 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
171 | ||
172 | os_free(format); | |
173 | } | |
174 | #endif /* CONFIG_NO_HOSTAPD_LOGGER */ | |
175 | ||
176 | ||
b6a7859d JM |
177 | /** |
178 | * hostapd_init - Allocate and initialize per-interface data | |
179 | * @config_file: Path to the configuration file | |
180 | * Returns: Pointer to the allocated interface data or %NULL on failure | |
181 | * | |
182 | * This function is used to allocate main data structures for per-interface | |
183 | * data. The allocated data buffer will be freed by calling | |
184 | * hostapd_cleanup_iface(). | |
185 | */ | |
186 | static struct hostapd_iface * hostapd_init(const char *config_file) | |
187 | { | |
188 | struct hostapd_iface *hapd_iface = NULL; | |
189 | struct hostapd_config *conf = NULL; | |
190 | struct hostapd_data *hapd; | |
191 | size_t i; | |
192 | ||
193 | hapd_iface = os_zalloc(sizeof(*hapd_iface)); | |
194 | if (hapd_iface == NULL) | |
195 | goto fail; | |
196 | ||
32da61d9 | 197 | hapd_iface->reload_config = hostapd_reload_config; |
41d719d6 | 198 | hapd_iface->config_read_cb = hostapd_config_read; |
b6a7859d JM |
199 | hapd_iface->config_fname = os_strdup(config_file); |
200 | if (hapd_iface->config_fname == NULL) | |
201 | goto fail; | |
70db2ab3 JM |
202 | hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init; |
203 | hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit; | |
1b56c26c | 204 | hapd_iface->for_each_interface = hostapd_for_each_interface; |
b6a7859d JM |
205 | |
206 | conf = hostapd_config_read(hapd_iface->config_fname); | |
207 | if (conf == NULL) | |
208 | goto fail; | |
209 | hapd_iface->conf = conf; | |
210 | ||
211 | hapd_iface->num_bss = conf->num_bss; | |
212 | hapd_iface->bss = os_zalloc(conf->num_bss * | |
213 | sizeof(struct hostapd_data *)); | |
214 | if (hapd_iface->bss == NULL) | |
215 | goto fail; | |
216 | ||
217 | for (i = 0; i < conf->num_bss; i++) { | |
218 | hapd = hapd_iface->bss[i] = | |
219 | hostapd_alloc_bss_data(hapd_iface, conf, | |
220 | &conf->bss[i]); | |
221 | if (hapd == NULL) | |
222 | goto fail; | |
bb437f28 | 223 | hapd->msg_ctx = hapd; |
b6a7859d JM |
224 | } |
225 | ||
226 | return hapd_iface; | |
227 | ||
228 | fail: | |
229 | if (conf) | |
230 | hostapd_config_free(conf); | |
231 | if (hapd_iface) { | |
b6a7859d JM |
232 | os_free(hapd_iface->config_fname); |
233 | os_free(hapd_iface->bss); | |
234 | os_free(hapd_iface); | |
235 | } | |
236 | return NULL; | |
237 | } | |
238 | ||
239 | ||
e5f2b59c JM |
240 | static int hostapd_driver_init(struct hostapd_iface *iface) |
241 | { | |
242 | struct wpa_init_params params; | |
243 | size_t i; | |
244 | struct hostapd_data *hapd = iface->bss[0]; | |
245 | struct hostapd_bss_config *conf = hapd->conf; | |
246 | u8 *b = conf->bssid; | |
2fee890a | 247 | struct wpa_driver_capa capa; |
e5f2b59c JM |
248 | |
249 | if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { | |
250 | wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); | |
251 | return -1; | |
252 | } | |
253 | ||
254 | /* Initialize the driver interface */ | |
255 | if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) | |
256 | b = NULL; | |
257 | ||
258 | os_memset(¶ms, 0, sizeof(params)); | |
4b24282a | 259 | for (i = 0; wpa_drivers[i]; i++) { |
7756114f JM |
260 | if (wpa_drivers[i] != hapd->driver) |
261 | continue; | |
262 | ||
263 | if (global.drv_priv[i] == NULL && | |
264 | wpa_drivers[i]->global_init) { | |
265 | global.drv_priv[i] = wpa_drivers[i]->global_init(); | |
266 | if (global.drv_priv[i] == NULL) { | |
267 | wpa_printf(MSG_ERROR, "Failed to initialize " | |
268 | "driver '%s'", | |
269 | wpa_drivers[i]->name); | |
270 | return -1; | |
271 | } | |
4b24282a | 272 | } |
7756114f JM |
273 | |
274 | params.global_priv = global.drv_priv[i]; | |
275 | break; | |
4b24282a | 276 | } |
e5f2b59c JM |
277 | params.bssid = b; |
278 | params.ifname = hapd->conf->iface; | |
279 | params.ssid = (const u8 *) hapd->conf->ssid.ssid; | |
280 | params.ssid_len = hapd->conf->ssid.ssid_len; | |
281 | params.test_socket = hapd->conf->test_socket; | |
282 | params.use_pae_group_addr = hapd->conf->use_pae_group_addr; | |
283 | ||
284 | params.num_bridge = hapd->iface->num_bss; | |
285 | params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *)); | |
286 | if (params.bridge == NULL) | |
287 | return -1; | |
288 | for (i = 0; i < hapd->iface->num_bss; i++) { | |
289 | struct hostapd_data *bss = hapd->iface->bss[i]; | |
290 | if (bss->conf->bridge[0]) | |
291 | params.bridge[i] = bss->conf->bridge; | |
292 | } | |
293 | ||
294 | params.own_addr = hapd->own_addr; | |
295 | ||
296 | hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); | |
297 | os_free(params.bridge); | |
298 | if (hapd->drv_priv == NULL) { | |
299 | wpa_printf(MSG_ERROR, "%s driver initialization failed.", | |
300 | hapd->driver->name); | |
301 | hapd->driver = NULL; | |
302 | return -1; | |
303 | } | |
304 | ||
2fee890a | 305 | if (hapd->driver->get_capa && |
4f73d88a | 306 | hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { |
2fee890a | 307 | iface->drv_flags = capa.flags; |
4f73d88a AN |
308 | iface->probe_resp_offloads = capa.probe_resp_offloads; |
309 | } | |
2fee890a | 310 | |
e5f2b59c JM |
311 | return 0; |
312 | } | |
313 | ||
314 | ||
f7c47833 JM |
315 | static void hostapd_interface_deinit_free(struct hostapd_iface *iface) |
316 | { | |
317 | const struct wpa_driver_ops *driver; | |
318 | void *drv_priv; | |
9078adfc JM |
319 | if (iface == NULL) |
320 | return; | |
f7c47833 JM |
321 | driver = iface->bss[0]->driver; |
322 | drv_priv = iface->bss[0]->drv_priv; | |
323 | hostapd_interface_deinit(iface); | |
324 | if (driver && driver->hapd_deinit) | |
325 | driver->hapd_deinit(drv_priv); | |
326 | hostapd_interface_free(iface); | |
327 | } | |
328 | ||
329 | ||
9969e5a4 JM |
330 | static struct hostapd_iface * |
331 | hostapd_interface_init(struct hapd_interfaces *interfaces, | |
332 | const char *config_fname, int debug) | |
5c333467 JM |
333 | { |
334 | struct hostapd_iface *iface; | |
335 | int k; | |
336 | ||
337 | wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); | |
338 | iface = hostapd_init(config_fname); | |
339 | if (!iface) | |
340 | return NULL; | |
9969e5a4 | 341 | iface->interfaces = interfaces; |
5c333467 JM |
342 | |
343 | for (k = 0; k < debug; k++) { | |
344 | if (iface->bss[0]->conf->logger_stdout_level > 0) | |
345 | iface->bss[0]->conf->logger_stdout_level--; | |
346 | } | |
347 | ||
e5f2b59c JM |
348 | if (hostapd_driver_init(iface) || |
349 | hostapd_setup_interface(iface)) { | |
f7c47833 | 350 | hostapd_interface_deinit_free(iface); |
5c333467 JM |
351 | return NULL; |
352 | } | |
353 | ||
354 | return iface; | |
355 | } | |
356 | ||
357 | ||
358 | /** | |
359 | * handle_term - SIGINT and SIGTERM handler to terminate hostapd process | |
360 | */ | |
0456ea16 | 361 | static void handle_term(int sig, void *signal_ctx) |
5c333467 JM |
362 | { |
363 | wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); | |
364 | eloop_terminate(); | |
365 | } | |
366 | ||
367 | ||
368 | #ifndef CONFIG_NATIVE_WINDOWS | |
a4f21109 JM |
369 | |
370 | static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) | |
371 | { | |
372 | if (hostapd_reload_config(iface) < 0) { | |
373 | wpa_printf(MSG_WARNING, "Failed to read new configuration " | |
374 | "file - continuing with old."); | |
375 | } | |
376 | return 0; | |
377 | } | |
378 | ||
379 | ||
5c333467 JM |
380 | /** |
381 | * handle_reload - SIGHUP handler to reload configuration | |
382 | */ | |
0456ea16 | 383 | static void handle_reload(int sig, void *signal_ctx) |
5c333467 | 384 | { |
0456ea16 | 385 | struct hapd_interfaces *interfaces = signal_ctx; |
5c333467 JM |
386 | wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", |
387 | sig); | |
9969e5a4 | 388 | hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); |
5c333467 JM |
389 | } |
390 | ||
391 | ||
0456ea16 | 392 | static void handle_dump_state(int sig, void *signal_ctx) |
5c333467 JM |
393 | { |
394 | #ifdef HOSTAPD_DUMP_STATE | |
0456ea16 | 395 | struct hapd_interfaces *interfaces = signal_ctx; |
9969e5a4 | 396 | hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); |
5c333467 JM |
397 | #endif /* HOSTAPD_DUMP_STATE */ |
398 | } | |
399 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
400 | ||
401 | ||
38e24575 JM |
402 | static int hostapd_global_init(struct hapd_interfaces *interfaces, |
403 | const char *entropy_file) | |
5c333467 | 404 | { |
4b24282a JM |
405 | int i; |
406 | ||
407 | os_memset(&global, 0, sizeof(global)); | |
408 | ||
5c333467 JM |
409 | hostapd_logger_register_cb(hostapd_logger_cb); |
410 | ||
411 | if (eap_server_register_methods()) { | |
412 | wpa_printf(MSG_ERROR, "Failed to register EAP methods"); | |
413 | return -1; | |
414 | } | |
415 | ||
0456ea16 | 416 | if (eloop_init()) { |
5c333467 JM |
417 | wpa_printf(MSG_ERROR, "Failed to initialize event loop"); |
418 | return -1; | |
419 | } | |
420 | ||
38e24575 | 421 | random_init(entropy_file); |
d47fa330 | 422 | |
5c333467 | 423 | #ifndef CONFIG_NATIVE_WINDOWS |
0456ea16 JM |
424 | eloop_register_signal(SIGHUP, handle_reload, interfaces); |
425 | eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); | |
5c333467 | 426 | #endif /* CONFIG_NATIVE_WINDOWS */ |
0456ea16 | 427 | eloop_register_signal_terminate(handle_term, interfaces); |
5c333467 JM |
428 | |
429 | #ifndef CONFIG_NATIVE_WINDOWS | |
430 | openlog("hostapd", 0, LOG_DAEMON); | |
431 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
432 | ||
4b24282a JM |
433 | for (i = 0; wpa_drivers[i]; i++) |
434 | global.drv_count++; | |
435 | if (global.drv_count == 0) { | |
436 | wpa_printf(MSG_ERROR, "No drivers enabled"); | |
437 | return -1; | |
438 | } | |
439 | global.drv_priv = os_zalloc(global.drv_count * sizeof(void *)); | |
440 | if (global.drv_priv == NULL) | |
441 | return -1; | |
4b24282a | 442 | |
5c333467 JM |
443 | return 0; |
444 | } | |
445 | ||
446 | ||
447 | static void hostapd_global_deinit(const char *pid_file) | |
448 | { | |
4b24282a JM |
449 | int i; |
450 | ||
451 | for (i = 0; wpa_drivers[i] && global.drv_priv; i++) { | |
452 | if (!global.drv_priv[i]) | |
453 | continue; | |
454 | wpa_drivers[i]->global_deinit(global.drv_priv[i]); | |
455 | } | |
456 | os_free(global.drv_priv); | |
457 | global.drv_priv = NULL; | |
458 | ||
5c333467 JM |
459 | #ifdef EAP_SERVER_TNC |
460 | tncs_global_deinit(); | |
461 | #endif /* EAP_SERVER_TNC */ | |
462 | ||
d47fa330 JM |
463 | random_deinit(); |
464 | ||
5c333467 JM |
465 | eloop_destroy(); |
466 | ||
467 | #ifndef CONFIG_NATIVE_WINDOWS | |
468 | closelog(); | |
469 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
470 | ||
471 | eap_server_unregister_methods(); | |
472 | ||
473 | os_daemonize_terminate(pid_file); | |
474 | } | |
475 | ||
476 | ||
477 | static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, | |
478 | const char *pid_file) | |
479 | { | |
480 | #ifdef EAP_SERVER_TNC | |
481 | int tnc = 0; | |
482 | size_t i, k; | |
483 | ||
484 | for (i = 0; !tnc && i < ifaces->count; i++) { | |
485 | for (k = 0; k < ifaces->iface[i]->num_bss; k++) { | |
486 | if (ifaces->iface[i]->bss[0]->conf->tnc) { | |
487 | tnc++; | |
488 | break; | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | if (tnc && tncs_global_init() < 0) { | |
494 | wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); | |
495 | return -1; | |
496 | } | |
497 | #endif /* EAP_SERVER_TNC */ | |
498 | ||
499 | if (daemonize && os_daemonize(pid_file)) { | |
500 | perror("daemon"); | |
501 | return -1; | |
502 | } | |
503 | ||
504 | eloop_run(); | |
505 | ||
506 | return 0; | |
507 | } | |
508 | ||
509 | ||
510 | static void show_version(void) | |
511 | { | |
512 | fprintf(stderr, | |
513 | "hostapd v" VERSION_STR "\n" | |
514 | "User space daemon for IEEE 802.11 AP management,\n" | |
515 | "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" | |
9e074973 | 516 | "Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> " |
5c333467 JM |
517 | "and contributors\n"); |
518 | } | |
519 | ||
520 | ||
521 | static void usage(void) | |
522 | { | |
523 | show_version(); | |
524 | fprintf(stderr, | |
525 | "\n" | |
38e24575 | 526 | "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] " |
5c333467 JM |
527 | "<configuration file(s)>\n" |
528 | "\n" | |
529 | "options:\n" | |
530 | " -h show this usage\n" | |
531 | " -d show more debug messages (-dd for even more)\n" | |
532 | " -B run daemon in the background\n" | |
38e24575 | 533 | " -e entropy file\n" |
5c333467 JM |
534 | " -P PID file\n" |
535 | " -K include key data in debug messages\n" | |
b41a47c0 BG |
536 | #ifdef CONFIG_DEBUG_FILE |
537 | " -f log output to debug file instead of stdout\n" | |
538 | #endif /* CONFIG_DEBUG_FILE */ | |
5c333467 JM |
539 | " -t include timestamps in some debug messages\n" |
540 | " -v show hostapd version\n"); | |
541 | ||
542 | exit(1); | |
543 | } | |
544 | ||
545 | ||
379ff7b9 BG |
546 | static const char * hostapd_msg_ifname_cb(void *ctx) |
547 | { | |
548 | struct hostapd_data *hapd = ctx; | |
549 | if (hapd && hapd->iconf && hapd->iconf->bss) | |
550 | return hapd->iconf->bss->iface; | |
551 | return NULL; | |
552 | } | |
553 | ||
554 | ||
5c333467 JM |
555 | int main(int argc, char *argv[]) |
556 | { | |
557 | struct hapd_interfaces interfaces; | |
558 | int ret = 1; | |
559 | size_t i; | |
560 | int c, debug = 0, daemonize = 0; | |
cedf9473 | 561 | char *pid_file = NULL; |
b41a47c0 | 562 | const char *log_file = NULL; |
38e24575 | 563 | const char *entropy_file = NULL; |
5c333467 | 564 | |
80d77c31 JM |
565 | if (os_program_init()) |
566 | return -1; | |
567 | ||
5c333467 | 568 | for (;;) { |
38e24575 | 569 | c = getopt(argc, argv, "Bde:f:hKP:tv"); |
5c333467 JM |
570 | if (c < 0) |
571 | break; | |
572 | switch (c) { | |
573 | case 'h': | |
574 | usage(); | |
575 | break; | |
576 | case 'd': | |
577 | debug++; | |
578 | if (wpa_debug_level > 0) | |
579 | wpa_debug_level--; | |
580 | break; | |
581 | case 'B': | |
582 | daemonize++; | |
583 | break; | |
38e24575 JM |
584 | case 'e': |
585 | entropy_file = optarg; | |
586 | break; | |
b41a47c0 BG |
587 | case 'f': |
588 | log_file = optarg; | |
589 | break; | |
5c333467 JM |
590 | case 'K': |
591 | wpa_debug_show_keys++; | |
592 | break; | |
593 | case 'P': | |
cedf9473 JM |
594 | os_free(pid_file); |
595 | pid_file = os_rel2abs_path(optarg); | |
5c333467 JM |
596 | break; |
597 | case 't': | |
598 | wpa_debug_timestamp++; | |
599 | break; | |
600 | case 'v': | |
601 | show_version(); | |
602 | exit(1); | |
603 | break; | |
604 | ||
605 | default: | |
606 | usage(); | |
607 | break; | |
608 | } | |
609 | } | |
610 | ||
611 | if (optind == argc) | |
612 | usage(); | |
613 | ||
379ff7b9 BG |
614 | wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); |
615 | ||
b41a47c0 BG |
616 | if (log_file) |
617 | wpa_debug_open_file(log_file); | |
618 | ||
5c333467 | 619 | interfaces.count = argc - optind; |
5b73735b | 620 | interfaces.iface = os_zalloc(interfaces.count * |
5c333467 JM |
621 | sizeof(struct hostapd_iface *)); |
622 | if (interfaces.iface == NULL) { | |
5b73735b | 623 | wpa_printf(MSG_ERROR, "malloc failed"); |
5c333467 JM |
624 | return -1; |
625 | } | |
626 | ||
38e24575 | 627 | if (hostapd_global_init(&interfaces, entropy_file)) |
5c333467 JM |
628 | return -1; |
629 | ||
630 | /* Initialize interfaces */ | |
631 | for (i = 0; i < interfaces.count; i++) { | |
9969e5a4 JM |
632 | interfaces.iface[i] = hostapd_interface_init(&interfaces, |
633 | argv[optind + i], | |
5c333467 JM |
634 | debug); |
635 | if (!interfaces.iface[i]) | |
636 | goto out; | |
637 | } | |
638 | ||
639 | if (hostapd_global_run(&interfaces, daemonize, pid_file)) | |
640 | goto out; | |
641 | ||
642 | ret = 0; | |
643 | ||
644 | out: | |
645 | /* Deinitialize all interfaces */ | |
f7c47833 JM |
646 | for (i = 0; i < interfaces.count; i++) |
647 | hostapd_interface_deinit_free(interfaces.iface[i]); | |
5c333467 JM |
648 | os_free(interfaces.iface); |
649 | ||
650 | hostapd_global_deinit(pid_file); | |
dd745de3 | 651 | os_free(pid_file); |
5c333467 | 652 | |
b41a47c0 BG |
653 | if (log_file) |
654 | wpa_debug_close_file(); | |
655 | ||
80d77c31 JM |
656 | os_program_deinit(); |
657 | ||
5c333467 JM |
658 | return ret; |
659 | } |