Move hostapd configuration parser into separate file
[libeap.git] / hostapd / main.c
1 /*
2  * hostapd / main()
3  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
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
15 #include "includes.h"
16 #ifndef CONFIG_NATIVE_WINDOWS
17 #include <syslog.h>
18 #endif /* CONFIG_NATIVE_WINDOWS */
19
20 #include "common.h"
21 #include "eloop.h"
22 #include "crypto/tls.h"
23 #include "common/version.h"
24 #include "eap_server/eap.h"
25 #include "eap_server/tncs.h"
26 #include "hostapd.h"
27 #include "config.h"
28 #include "config_file.h"
29
30
31 extern int wpa_debug_level;
32 extern int wpa_debug_show_keys;
33 extern int wpa_debug_timestamp;
34
35
36 struct hapd_interfaces {
37         size_t count;
38         struct hostapd_iface **iface;
39 };
40
41
42 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
43                                int (*cb)(struct hostapd_iface *iface,
44                                          void *ctx), void *ctx)
45 {
46         size_t i;
47         int ret;
48
49         for (i = 0; i < interfaces->count; i++) {
50                 ret = cb(interfaces->iface[i], ctx);
51                 if (ret)
52                         return ret;
53         }
54
55         return 0;
56 }
57
58
59 #ifndef CONFIG_NO_HOSTAPD_LOGGER
60 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
61                               int level, const char *txt, size_t len)
62 {
63         struct hostapd_data *hapd = ctx;
64         char *format, *module_str;
65         int maxlen;
66         int conf_syslog_level, conf_stdout_level;
67         unsigned int conf_syslog, conf_stdout;
68
69         maxlen = len + 100;
70         format = os_malloc(maxlen);
71         if (!format)
72                 return;
73
74         if (hapd && hapd->conf) {
75                 conf_syslog_level = hapd->conf->logger_syslog_level;
76                 conf_stdout_level = hapd->conf->logger_stdout_level;
77                 conf_syslog = hapd->conf->logger_syslog;
78                 conf_stdout = hapd->conf->logger_stdout;
79         } else {
80                 conf_syslog_level = conf_stdout_level = 0;
81                 conf_syslog = conf_stdout = (unsigned int) -1;
82         }
83
84         switch (module) {
85         case HOSTAPD_MODULE_IEEE80211:
86                 module_str = "IEEE 802.11";
87                 break;
88         case HOSTAPD_MODULE_IEEE8021X:
89                 module_str = "IEEE 802.1X";
90                 break;
91         case HOSTAPD_MODULE_RADIUS:
92                 module_str = "RADIUS";
93                 break;
94         case HOSTAPD_MODULE_WPA:
95                 module_str = "WPA";
96                 break;
97         case HOSTAPD_MODULE_DRIVER:
98                 module_str = "DRIVER";
99                 break;
100         case HOSTAPD_MODULE_IAPP:
101                 module_str = "IAPP";
102                 break;
103         case HOSTAPD_MODULE_MLME:
104                 module_str = "MLME";
105                 break;
106         default:
107                 module_str = NULL;
108                 break;
109         }
110
111         if (hapd && hapd->conf && addr)
112                 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
113                             hapd->conf->iface, MAC2STR(addr),
114                             module_str ? " " : "", module_str, txt);
115         else if (hapd && hapd->conf)
116                 os_snprintf(format, maxlen, "%s:%s%s %s",
117                             hapd->conf->iface, module_str ? " " : "",
118                             module_str, txt);
119         else if (addr)
120                 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
121                             MAC2STR(addr), module_str ? " " : "",
122                             module_str, txt);
123         else
124                 os_snprintf(format, maxlen, "%s%s%s",
125                             module_str, module_str ? ": " : "", txt);
126
127         if ((conf_stdout & module) && level >= conf_stdout_level) {
128                 wpa_debug_print_timestamp();
129                 printf("%s\n", format);
130         }
131
132 #ifndef CONFIG_NATIVE_WINDOWS
133         if ((conf_syslog & module) && level >= conf_syslog_level) {
134                 int priority;
135                 switch (level) {
136                 case HOSTAPD_LEVEL_DEBUG_VERBOSE:
137                 case HOSTAPD_LEVEL_DEBUG:
138                         priority = LOG_DEBUG;
139                         break;
140                 case HOSTAPD_LEVEL_INFO:
141                         priority = LOG_INFO;
142                         break;
143                 case HOSTAPD_LEVEL_NOTICE:
144                         priority = LOG_NOTICE;
145                         break;
146                 case HOSTAPD_LEVEL_WARNING:
147                         priority = LOG_WARNING;
148                         break;
149                 default:
150                         priority = LOG_INFO;
151                         break;
152                 }
153                 syslog(priority, "%s", format);
154         }
155 #endif /* CONFIG_NATIVE_WINDOWS */
156
157         os_free(format);
158 }
159 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
160
161
162 /**
163  * hostapd_init - Allocate and initialize per-interface data
164  * @config_file: Path to the configuration file
165  * Returns: Pointer to the allocated interface data or %NULL on failure
166  *
167  * This function is used to allocate main data structures for per-interface
168  * data. The allocated data buffer will be freed by calling
169  * hostapd_cleanup_iface().
170  */
171 static struct hostapd_iface * hostapd_init(const char *config_file)
172 {
173         struct hostapd_iface *hapd_iface = NULL;
174         struct hostapd_config *conf = NULL;
175         struct hostapd_data *hapd;
176         size_t i;
177
178         hapd_iface = os_zalloc(sizeof(*hapd_iface));
179         if (hapd_iface == NULL)
180                 goto fail;
181
182         hapd_iface->config_read_cb = hostapd_config_read;
183         hapd_iface->config_fname = os_strdup(config_file);
184         if (hapd_iface->config_fname == NULL)
185                 goto fail;
186
187         conf = hostapd_config_read(hapd_iface->config_fname);
188         if (conf == NULL)
189                 goto fail;
190         hapd_iface->conf = conf;
191
192         hapd_iface->num_bss = conf->num_bss;
193         hapd_iface->bss = os_zalloc(conf->num_bss *
194                                     sizeof(struct hostapd_data *));
195         if (hapd_iface->bss == NULL)
196                 goto fail;
197
198         for (i = 0; i < conf->num_bss; i++) {
199                 hapd = hapd_iface->bss[i] =
200                         hostapd_alloc_bss_data(hapd_iface, conf,
201                                                &conf->bss[i]);
202                 if (hapd == NULL)
203                         goto fail;
204         }
205
206         return hapd_iface;
207
208 fail:
209         if (conf)
210                 hostapd_config_free(conf);
211         if (hapd_iface) {
212                 for (i = 0; hapd_iface->bss && i < hapd_iface->num_bss; i++) {
213                         hapd = hapd_iface->bss[i];
214                         if (hapd && hapd->ssl_ctx)
215                                 tls_deinit(hapd->ssl_ctx);
216                 }
217
218                 os_free(hapd_iface->config_fname);
219                 os_free(hapd_iface->bss);
220                 os_free(hapd_iface);
221         }
222         return NULL;
223 }
224
225
226 static struct hostapd_iface *
227 hostapd_interface_init(struct hapd_interfaces *interfaces,
228                        const char *config_fname, int debug)
229 {
230         struct hostapd_iface *iface;
231         int k;
232
233         wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
234         iface = hostapd_init(config_fname);
235         if (!iface)
236                 return NULL;
237         iface->interfaces = interfaces;
238
239         for (k = 0; k < debug; k++) {
240                 if (iface->bss[0]->conf->logger_stdout_level > 0)
241                         iface->bss[0]->conf->logger_stdout_level--;
242         }
243
244         if (hostapd_setup_interface(iface)) {
245                 hostapd_interface_deinit(iface);
246                 return NULL;
247         }
248
249         return iface;
250 }
251
252
253 /**
254  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
255  */
256 static void handle_term(int sig, void *signal_ctx)
257 {
258         wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
259         eloop_terminate();
260 }
261
262
263 #ifndef CONFIG_NATIVE_WINDOWS
264 /**
265  * handle_reload - SIGHUP handler to reload configuration
266  */
267 static void handle_reload(int sig, void *signal_ctx)
268 {
269         struct hapd_interfaces *interfaces = signal_ctx;
270         wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
271                    sig);
272         hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
273 }
274
275
276 static void handle_dump_state(int sig, void *signal_ctx)
277 {
278 #ifdef HOSTAPD_DUMP_STATE
279         struct hapd_interfaces *interfaces = signal_ctx;
280         hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
281 #endif /* HOSTAPD_DUMP_STATE */
282 }
283 #endif /* CONFIG_NATIVE_WINDOWS */
284
285
286 static int hostapd_global_init(struct hapd_interfaces *interfaces)
287 {
288         hostapd_logger_register_cb(hostapd_logger_cb);
289
290         if (eap_server_register_methods()) {
291                 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
292                 return -1;
293         }
294
295         if (eloop_init()) {
296                 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
297                 return -1;
298         }
299
300 #ifndef CONFIG_NATIVE_WINDOWS
301         eloop_register_signal(SIGHUP, handle_reload, interfaces);
302         eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
303 #endif /* CONFIG_NATIVE_WINDOWS */
304         eloop_register_signal_terminate(handle_term, interfaces);
305
306 #ifndef CONFIG_NATIVE_WINDOWS
307         openlog("hostapd", 0, LOG_DAEMON);
308 #endif /* CONFIG_NATIVE_WINDOWS */
309
310         return 0;
311 }
312
313
314 static void hostapd_global_deinit(const char *pid_file)
315 {
316 #ifdef EAP_SERVER_TNC
317         tncs_global_deinit();
318 #endif /* EAP_SERVER_TNC */
319
320         eloop_destroy();
321
322 #ifndef CONFIG_NATIVE_WINDOWS
323         closelog();
324 #endif /* CONFIG_NATIVE_WINDOWS */
325
326         eap_server_unregister_methods();
327
328         os_daemonize_terminate(pid_file);
329 }
330
331
332 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
333                               const char *pid_file)
334 {
335 #ifdef EAP_SERVER_TNC
336         int tnc = 0;
337         size_t i, k;
338
339         for (i = 0; !tnc && i < ifaces->count; i++) {
340                 for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
341                         if (ifaces->iface[i]->bss[0]->conf->tnc) {
342                                 tnc++;
343                                 break;
344                         }
345                 }
346         }
347
348         if (tnc && tncs_global_init() < 0) {
349                 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
350                 return -1;
351         }
352 #endif /* EAP_SERVER_TNC */
353
354         if (daemonize && os_daemonize(pid_file)) {
355                 perror("daemon");
356                 return -1;
357         }
358
359         eloop_run();
360
361         return 0;
362 }
363
364
365 static void show_version(void)
366 {
367         fprintf(stderr,
368                 "hostapd v" VERSION_STR "\n"
369                 "User space daemon for IEEE 802.11 AP management,\n"
370                 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
371                 "Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> "
372                 "and contributors\n");
373 }
374
375
376 static void usage(void)
377 {
378         show_version();
379         fprintf(stderr,
380                 "\n"
381                 "usage: hostapd [-hdBKtv] [-P <PID file>] "
382                 "<configuration file(s)>\n"
383                 "\n"
384                 "options:\n"
385                 "   -h   show this usage\n"
386                 "   -d   show more debug messages (-dd for even more)\n"
387                 "   -B   run daemon in the background\n"
388                 "   -P   PID file\n"
389                 "   -K   include key data in debug messages\n"
390                 "   -t   include timestamps in some debug messages\n"
391                 "   -v   show hostapd version\n");
392
393         exit(1);
394 }
395
396
397 int main(int argc, char *argv[])
398 {
399         struct hapd_interfaces interfaces;
400         int ret = 1;
401         size_t i;
402         int c, debug = 0, daemonize = 0;
403         char *pid_file = NULL;
404
405         if (os_program_init())
406                 return -1;
407
408         for (;;) {
409                 c = getopt(argc, argv, "BdhKP:tv");
410                 if (c < 0)
411                         break;
412                 switch (c) {
413                 case 'h':
414                         usage();
415                         break;
416                 case 'd':
417                         debug++;
418                         if (wpa_debug_level > 0)
419                                 wpa_debug_level--;
420                         break;
421                 case 'B':
422                         daemonize++;
423                         break;
424                 case 'K':
425                         wpa_debug_show_keys++;
426                         break;
427                 case 'P':
428                         os_free(pid_file);
429                         pid_file = os_rel2abs_path(optarg);
430                         break;
431                 case 't':
432                         wpa_debug_timestamp++;
433                         break;
434                 case 'v':
435                         show_version();
436                         exit(1);
437                         break;
438
439                 default:
440                         usage();
441                         break;
442                 }
443         }
444
445         if (optind == argc)
446                 usage();
447
448         interfaces.count = argc - optind;
449         interfaces.iface = os_malloc(interfaces.count *
450                                      sizeof(struct hostapd_iface *));
451         if (interfaces.iface == NULL) {
452                 wpa_printf(MSG_ERROR, "malloc failed\n");
453                 return -1;
454         }
455
456         if (hostapd_global_init(&interfaces))
457                 return -1;
458
459         /* Initialize interfaces */
460         for (i = 0; i < interfaces.count; i++) {
461                 interfaces.iface[i] = hostapd_interface_init(&interfaces,
462                                                              argv[optind + i],
463                                                              debug);
464                 if (!interfaces.iface[i])
465                         goto out;
466         }
467
468         if (hostapd_global_run(&interfaces, daemonize, pid_file))
469                 goto out;
470
471         ret = 0;
472
473  out:
474         /* Deinitialize all interfaces */
475         for (i = 0; i < interfaces.count; i++)
476                 hostapd_interface_deinit(interfaces.iface[i]);
477         os_free(interfaces.iface);
478
479         hostapd_global_deinit(pid_file);
480         os_free(pid_file);
481
482         os_program_deinit();
483
484         return ret;
485 }