]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/main.c
Maintain internal copy of Probe Response offload capabilities
[thirdparty/hostap.git] / hostapd / main.c
CommitLineData
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
36extern int wpa_debug_level;
37extern int wpa_debug_show_keys;
38extern int wpa_debug_timestamp;
39
4b24282a
JM
40extern struct wpa_driver_ops *wpa_drivers[];
41
42
43struct hapd_global {
44 void **drv_priv;
45 size_t drv_count;
46};
47
48static struct hapd_global global;
49
5c333467
JM
50
51struct hapd_interfaces {
52 size_t count;
53 struct hostapd_iface **iface;
54};
55
56
1b56c26c
JM
57static 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
75static 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 */
186static 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
228fail:
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
240static 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(&params, 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, &params);
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
315static 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
330static struct hostapd_iface *
331hostapd_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 361static 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
370static 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 383static 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 392static 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
402static 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
447static 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
477static 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
510static 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
521static 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
546static 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
555int 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}