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 "ap/ap_drv_ops.h"
25#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
35extern 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
45
46#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->config_fname = os_strdup(config_file);
170	if (hapd_iface->config_fname == NULL)
171		goto fail;
172
173	conf = hostapd_config_read(hapd_iface->config_fname);
174	if (conf == NULL)
175		goto fail;
176	hapd_iface->conf = conf;
177
178	hapd_iface->num_bss = conf->num_bss;
179	hapd_iface->bss = os_calloc(conf->num_bss,
180				    sizeof(struct hostapd_data *));
181	if (hapd_iface->bss == NULL)
182		goto fail;
183
184	for (i = 0; i < conf->num_bss; i++) {
185		hapd = hapd_iface->bss[i] =
186			hostapd_alloc_bss_data(hapd_iface, conf,
187					       &conf->bss[i]);
188		if (hapd == NULL)
189			goto fail;
190		hapd->msg_ctx = hapd;
191	}
192
193	return hapd_iface;
194
195fail:
196	if (conf)
197		hostapd_config_free(conf);
198	if (hapd_iface) {
199		os_free(hapd_iface->config_fname);
200		os_free(hapd_iface->bss);
201		os_free(hapd_iface);
202	}
203	return NULL;
204}
205
206
207static int hostapd_driver_init(struct hostapd_iface *iface)
208{
209	struct wpa_init_params params;
210	size_t i;
211	struct hostapd_data *hapd = iface->bss[0];
212	struct hostapd_bss_config *conf = hapd->conf;
213	u8 *b = conf->bssid;
214	struct wpa_driver_capa capa;
215
216	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
217		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
218		return -1;
219	}
220
221	/* Initialize the driver interface */
222	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
223		b = NULL;
224
225	os_memset(&params, 0, sizeof(params));
226	for (i = 0; wpa_drivers[i]; i++) {
227		if (wpa_drivers[i] != hapd->driver)
228			continue;
229
230		if (global.drv_priv[i] == NULL &&
231		    wpa_drivers[i]->global_init) {
232			global.drv_priv[i] = wpa_drivers[i]->global_init();
233			if (global.drv_priv[i] == NULL) {
234				wpa_printf(MSG_ERROR, "Failed to initialize "
235					   "driver '%s'",
236					   wpa_drivers[i]->name);
237				return -1;
238			}
239		}
240
241		params.global_priv = global.drv_priv[i];
242		break;
243	}
244	params.bssid = b;
245	params.ifname = hapd->conf->iface;
246	params.ssid = hapd->conf->ssid.ssid;
247	params.ssid_len = hapd->conf->ssid.ssid_len;
248	params.test_socket = hapd->conf->test_socket;
249	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
250
251	params.num_bridge = hapd->iface->num_bss;
252	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
253	if (params.bridge == NULL)
254		return -1;
255	for (i = 0; i < hapd->iface->num_bss; i++) {
256		struct hostapd_data *bss = hapd->iface->bss[i];
257		if (bss->conf->bridge[0])
258			params.bridge[i] = bss->conf->bridge;
259	}
260
261	params.own_addr = hapd->own_addr;
262
263	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
264	os_free(params.bridge);
265	if (hapd->drv_priv == NULL) {
266		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
267			   hapd->driver->name);
268		hapd->driver = NULL;
269		return -1;
270	}
271
272	if (hapd->driver->get_capa &&
273	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
274		iface->drv_flags = capa.flags;
275		iface->probe_resp_offloads = capa.probe_resp_offloads;
276	}
277
278	return 0;
279}
280
281
282static struct hostapd_iface *
283hostapd_interface_init(struct hapd_interfaces *interfaces,
284		       const char *config_fname, int debug)
285{
286	struct hostapd_iface *iface;
287	int k;
288
289	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
290	iface = hostapd_init(config_fname);
291	if (!iface)
292		return NULL;
293	iface->interfaces = interfaces;
294
295	for (k = 0; k < debug; k++) {
296		if (iface->bss[0]->conf->logger_stdout_level > 0)
297			iface->bss[0]->conf->logger_stdout_level--;
298	}
299
300	if (iface->conf->bss[0].iface[0] != 0 ||
301	    hostapd_drv_none(iface->bss[0])) {
302		if (hostapd_driver_init(iface) ||
303			hostapd_setup_interface(iface)) {
304			hostapd_interface_deinit_free(iface);
305			return NULL;
306		}
307	}
308
309	return iface;
310}
311
312
313/**
314 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
315 */
316static void handle_term(int sig, void *signal_ctx)
317{
318	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
319	eloop_terminate();
320}
321
322
323#ifndef CONFIG_NATIVE_WINDOWS
324
325static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
326{
327	if (hostapd_reload_config(iface) < 0) {
328		wpa_printf(MSG_WARNING, "Failed to read new configuration "
329			   "file - continuing with old.");
330	}
331	return 0;
332}
333
334
335/**
336 * handle_reload - SIGHUP handler to reload configuration
337 */
338static void handle_reload(int sig, void *signal_ctx)
339{
340	struct hapd_interfaces *interfaces = signal_ctx;
341	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
342		   sig);
343	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
344}
345
346
347static void handle_dump_state(int sig, void *signal_ctx)
348{
349#ifdef HOSTAPD_DUMP_STATE
350	struct hapd_interfaces *interfaces = signal_ctx;
351	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
352#endif /* HOSTAPD_DUMP_STATE */
353}
354#endif /* CONFIG_NATIVE_WINDOWS */
355
356
357static int hostapd_global_init(struct hapd_interfaces *interfaces,
358			       const char *entropy_file)
359{
360	int i;
361
362	os_memset(&global, 0, sizeof(global));
363
364	hostapd_logger_register_cb(hostapd_logger_cb);
365
366	if (eap_server_register_methods()) {
367		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
368		return -1;
369	}
370
371	if (eloop_init()) {
372		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
373		return -1;
374	}
375
376	random_init(entropy_file);
377
378#ifndef CONFIG_NATIVE_WINDOWS
379	eloop_register_signal(SIGHUP, handle_reload, interfaces);
380	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
381#endif /* CONFIG_NATIVE_WINDOWS */
382	eloop_register_signal_terminate(handle_term, interfaces);
383
384#ifndef CONFIG_NATIVE_WINDOWS
385	openlog("hostapd", 0, LOG_DAEMON);
386#endif /* CONFIG_NATIVE_WINDOWS */
387
388	for (i = 0; wpa_drivers[i]; i++)
389		global.drv_count++;
390	if (global.drv_count == 0) {
391		wpa_printf(MSG_ERROR, "No drivers enabled");
392		return -1;
393	}
394	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
395	if (global.drv_priv == NULL)
396		return -1;
397
398	return 0;
399}
400
401
402static void hostapd_global_deinit(const char *pid_file)
403{
404	int i;
405
406	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
407		if (!global.drv_priv[i])
408			continue;
409		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
410	}
411	os_free(global.drv_priv);
412	global.drv_priv = NULL;
413
414#ifdef EAP_SERVER_TNC
415	tncs_global_deinit();
416#endif /* EAP_SERVER_TNC */
417
418	random_deinit();
419
420	eloop_destroy();
421
422#ifndef CONFIG_NATIVE_WINDOWS
423	closelog();
424#endif /* CONFIG_NATIVE_WINDOWS */
425
426	eap_server_unregister_methods();
427
428	os_daemonize_terminate(pid_file);
429}
430
431
432static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
433			      const char *pid_file)
434{
435#ifdef EAP_SERVER_TNC
436	int tnc = 0;
437	size_t i, k;
438
439	for (i = 0; !tnc && i < ifaces->count; i++) {
440		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
441			if (ifaces->iface[i]->bss[0]->conf->tnc) {
442				tnc++;
443				break;
444			}
445		}
446	}
447
448	if (tnc && tncs_global_init() < 0) {
449		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
450		return -1;
451	}
452#endif /* EAP_SERVER_TNC */
453
454	if (daemonize && os_daemonize(pid_file)) {
455		perror("daemon");
456		return -1;
457	}
458
459	eloop_run();
460
461	return 0;
462}
463
464
465static void show_version(void)
466{
467	fprintf(stderr,
468		"hostapd v" VERSION_STR "\n"
469		"User space daemon for IEEE 802.11 AP management,\n"
470		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
471		"Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
472		"and contributors\n");
473}
474
475
476static void usage(void)
477{
478	show_version();
479	fprintf(stderr,
480		"\n"
481		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
482		"\\\n"
483		"         [-g <global ctrl_iface>] <configuration file(s)>\n"
484		"\n"
485		"options:\n"
486		"   -h   show this usage\n"
487		"   -d   show more debug messages (-dd for even more)\n"
488		"   -B   run daemon in the background\n"
489		"   -e   entropy file\n"
490		"   -g   global control interface path\n"
491		"   -P   PID file\n"
492		"   -K   include key data in debug messages\n"
493#ifdef CONFIG_DEBUG_FILE
494		"   -f   log output to debug file instead of stdout\n"
495#endif /* CONFIG_DEBUG_FILE */
496		"   -t   include timestamps in some debug messages\n"
497		"   -v   show hostapd version\n");
498
499	exit(1);
500}
501
502
503static const char * hostapd_msg_ifname_cb(void *ctx)
504{
505	struct hostapd_data *hapd = ctx;
506	if (hapd && hapd->iconf && hapd->iconf->bss)
507		return hapd->iconf->bss->iface;
508	return NULL;
509}
510
511
512static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
513					 const char *path)
514{
515	char *pos;
516	os_free(interfaces->global_iface_path);
517	interfaces->global_iface_path = os_strdup(path);
518	if (interfaces->global_iface_path == NULL)
519		return -1;
520	pos = os_strrchr(interfaces->global_iface_path, '/');
521	if (pos == NULL) {
522		os_free(interfaces->global_iface_path);
523		interfaces->global_iface_path = NULL;
524		return -1;
525	}
526
527	*pos = '\0';
528	interfaces->global_iface_name = pos + 1;
529
530	return 0;
531}
532
533
534int main(int argc, char *argv[])
535{
536	struct hapd_interfaces interfaces;
537	int ret = 1;
538	size_t i;
539	int c, debug = 0, daemonize = 0;
540	char *pid_file = NULL;
541	const char *log_file = NULL;
542	const char *entropy_file = NULL;
543
544	if (os_program_init())
545		return -1;
546
547	os_memset(&interfaces, 0, sizeof(interfaces));
548	interfaces.reload_config = hostapd_reload_config;
549	interfaces.config_read_cb = hostapd_config_read;
550	interfaces.for_each_interface = hostapd_for_each_interface;
551	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
552	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
553	interfaces.driver_init = hostapd_driver_init;
554	interfaces.global_iface_path = NULL;
555	interfaces.global_iface_name = NULL;
556	interfaces.global_ctrl_sock = -1;
557
558	for (;;) {
559		c = getopt(argc, argv, "Bde:f:hKP:tvg:");
560		if (c < 0)
561			break;
562		switch (c) {
563		case 'h':
564			usage();
565			break;
566		case 'd':
567			debug++;
568			if (wpa_debug_level > 0)
569				wpa_debug_level--;
570			break;
571		case 'B':
572			daemonize++;
573			break;
574		case 'e':
575			entropy_file = optarg;
576			break;
577		case 'f':
578			log_file = optarg;
579			break;
580		case 'K':
581			wpa_debug_show_keys++;
582			break;
583		case 'P':
584			os_free(pid_file);
585			pid_file = os_rel2abs_path(optarg);
586			break;
587		case 't':
588			wpa_debug_timestamp++;
589			break;
590		case 'v':
591			show_version();
592			exit(1);
593			break;
594		case 'g':
595			hostapd_get_global_ctrl_iface(&interfaces, optarg);
596			break;
597
598		default:
599			usage();
600			break;
601		}
602	}
603
604	if (optind == argc && interfaces.global_iface_path == NULL)
605		usage();
606
607	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
608
609	if (log_file)
610		wpa_debug_open_file(log_file);
611
612	interfaces.count = argc - optind;
613	if (interfaces.count) {
614		interfaces.iface = os_calloc(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
622	if (hostapd_global_init(&interfaces, entropy_file))
623		return -1;
624
625	/* Initialize interfaces */
626	for (i = 0; i < interfaces.count; i++) {
627		interfaces.iface[i] = hostapd_interface_init(&interfaces,
628							     argv[optind + i],
629							     debug);
630		if (!interfaces.iface[i])
631			goto out;
632	}
633
634	hostapd_global_ctrl_iface_init(&interfaces);
635
636	if (hostapd_global_run(&interfaces, daemonize, pid_file))
637		goto out;
638
639	ret = 0;
640
641 out:
642	hostapd_global_ctrl_iface_deinit(&interfaces);
643	/* Deinitialize all interfaces */
644	for (i = 0; i < interfaces.count; i++)
645		hostapd_interface_deinit_free(interfaces.iface[i]);
646	os_free(interfaces.iface);
647
648	hostapd_global_deinit(pid_file);
649	os_free(pid_file);
650
651	if (log_file)
652		wpa_debug_close_file();
653
654	os_program_deinit();
655
656	return ret;
657}
658