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