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