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