blob: 36c2238375ac40b5b7674483cfee30521ed67cf5 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * hostapd / main()
3 * Copyright (c) 2002-2022, 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#include <grp.h>
13#endif /* CONFIG_NATIVE_WINDOWS */
14
15#include "utils/common.h"
16#include "utils/eloop.h"
17#include "utils/uuid.h"
18#include "crypto/crypto.h"
19#include "crypto/random.h"
20#include "crypto/tls.h"
21#include "common/version.h"
22#include "common/dpp.h"
23#include "drivers/driver.h"
24#include "eap_server/eap.h"
25#include "eap_server/tncs.h"
26#include "ap/hostapd.h"
27#include "ap/ap_config.h"
28#include "ap/ap_drv_ops.h"
29#include "ap/dpp_hostapd.h"
30#include "fst/fst.h"
31#include "config_file.h"
32#include "eap_register.h"
33#include "ctrl_iface.h"
34#include "build_features.h"
35
36struct hapd_global {
37 void **drv_priv;
38 size_t drv_count;
39};
40
41static struct hapd_global global;
42static int daemonize = 0;
43static char *pid_file = NULL;
44
45extern int radius_main(int argc, char **argv);
46
47#ifndef CONFIG_NO_HOSTAPD_LOGGER
48static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
49 int level, const char *txt, size_t len)
50{
51 struct hostapd_data *hapd = ctx;
52 char *format, *module_str;
53 int maxlen;
54 int conf_syslog_level, conf_stdout_level;
55 unsigned int conf_syslog, conf_stdout;
56
57 maxlen = len + 100;
58 format = os_malloc(maxlen);
59 if (!format)
60 return;
61
62 if (hapd && hapd->conf) {
63 conf_syslog_level = hapd->conf->logger_syslog_level;
64 conf_stdout_level = hapd->conf->logger_stdout_level;
65 conf_syslog = hapd->conf->logger_syslog;
66 conf_stdout = hapd->conf->logger_stdout;
67 } else {
68 conf_syslog_level = conf_stdout_level = 0;
69 conf_syslog = conf_stdout = (unsigned int) -1;
70 }
71
72 switch (module) {
73 case HOSTAPD_MODULE_IEEE80211:
74 module_str = "IEEE 802.11";
75 break;
76 case HOSTAPD_MODULE_IEEE8021X:
77 module_str = "IEEE 802.1X";
78 break;
79 case HOSTAPD_MODULE_RADIUS:
80 module_str = "RADIUS";
81 break;
82 case HOSTAPD_MODULE_WPA:
83 module_str = "WPA";
84 break;
85 case HOSTAPD_MODULE_DRIVER:
86 module_str = "DRIVER";
87 break;
88 case HOSTAPD_MODULE_MLME:
89 module_str = "MLME";
90 break;
91 default:
92 module_str = NULL;
93 break;
94 }
95
96 if (hapd && hapd->conf && addr)
97 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
98 hapd->conf->iface, MAC2STR(addr),
99 module_str ? " " : "", module_str ? module_str : "",
100 txt);
101 else if (hapd && hapd->conf)
102 os_snprintf(format, maxlen, "%s:%s%s %s",
103 hapd->conf->iface, module_str ? " " : "",
104 module_str ? module_str : "", txt);
105 else if (addr)
106 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
107 MAC2STR(addr), module_str ? " " : "",
108 module_str ? module_str : "", txt);
109 else
110 os_snprintf(format, maxlen, "%s%s%s",
111 module_str ? module_str : "",
112 module_str ? ": " : "", txt);
113
114#ifdef CONFIG_DEBUG_SYSLOG
115 if (wpa_debug_syslog)
116 conf_stdout = 0;
117#endif /* CONFIG_DEBUG_SYSLOG */
118 if ((conf_stdout & module) && level >= conf_stdout_level) {
119 wpa_debug_print_timestamp();
120 wpa_printf(MSG_INFO, "%s", format);
121 }
122
123#ifndef CONFIG_NATIVE_WINDOWS
124 if ((conf_syslog & module) && level >= conf_syslog_level) {
125 int priority;
126 switch (level) {
127 case HOSTAPD_LEVEL_DEBUG_VERBOSE:
128 case HOSTAPD_LEVEL_DEBUG:
129 priority = LOG_DEBUG;
130 break;
131 case HOSTAPD_LEVEL_INFO:
132 priority = LOG_INFO;
133 break;
134 case HOSTAPD_LEVEL_NOTICE:
135 priority = LOG_NOTICE;
136 break;
137 case HOSTAPD_LEVEL_WARNING:
138 priority = LOG_WARNING;
139 break;
140 default:
141 priority = LOG_INFO;
142 break;
143 }
144 syslog(priority, "%s", format);
145 }
146#endif /* CONFIG_NATIVE_WINDOWS */
147
148 os_free(format);
149}
150#endif /* CONFIG_NO_HOSTAPD_LOGGER */
151
152static void hostapd_setup_complete_cb(void *ctx)
153{
154 if (daemonize && os_daemonize(pid_file)) {
155 perror("daemon");
156 return;
157 }
158 daemonize = 0;
159}
160
161/**
162 * hostapd_driver_init - Preparate driver interface
163 */
164static int hostapd_driver_init(struct hostapd_iface *iface)
165{
166 struct wpa_init_params params;
167 size_t i;
168 struct hostapd_data *hapd = iface->bss[0];
169 struct hostapd_bss_config *conf = hapd->conf;
170 u8 *b = conf->bssid;
171 struct wpa_driver_capa capa;
172
173 if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
174 wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
175 return -1;
176 }
177
178#ifdef CONFIG_IEEE80211BE
179 for (i = 0; conf->mld_ap && i < iface->interfaces->count; i++) {
180 struct hostapd_iface *h = iface->interfaces->iface[i];
181 struct hostapd_data *h_hapd = h->bss[0];
182 struct hostapd_bss_config *hconf = h_hapd->conf;
183
184 if (h == iface) {
185 wpa_printf(MSG_DEBUG, "MLD: Skip own interface");
186 continue;
187 }
188
189 if (!hconf->mld_ap || hconf->mld_id != conf->mld_id) {
190 wpa_printf(MSG_DEBUG,
191 "MLD: Skip non matching mld_id");
192 continue;
193 }
194
195 wpa_printf(MSG_DEBUG, "MLD: Found matching MLD interface");
196 if (!h_hapd->drv_priv) {
197 wpa_printf(MSG_DEBUG,
198 "MLD: Matching MLD BSS not initialized yet");
199 continue;
200 }
201
202 hapd->drv_priv = h_hapd->drv_priv;
203
204 /*
205 * All interfaces participating in the AP MLD would have
206 * the same MLD address, which is the interface hardware
207 * address, while the interface address would be
208 * derived from the original interface address if BSSID
209 * is not configured, and otherwise it would be the
210 * configured BSSID.
211 */
212 os_memcpy(hapd->mld_addr, h_hapd->mld_addr, ETH_ALEN);
213 if (is_zero_ether_addr(b)) {
214 os_memcpy(hapd->own_addr, h_hapd->mld_addr, ETH_ALEN);
215 random_mac_addr_keep_oui(hapd->own_addr);
216 } else {
217 os_memcpy(hapd->own_addr, b, ETH_ALEN);
218 }
219
220 /*
221 * Mark the interface as a secondary interface, as this
222 * is needed for the de-initialization flow
223 */
224 hapd->mld_first_bss = h_hapd;
225 hapd->mld_link_id = hapd->mld_first_bss->mld_next_link_id++;
226
227 goto setup_mld;
228 }
229#endif /* CONFIG_IEEE80211BE */
230
231 hapd->setup_complete_cb = hostapd_setup_complete_cb;
232
233 /* Initialize the driver interface */
234 if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
235 b = NULL;
236
237 os_memset(&params, 0, sizeof(params));
238 for (i = 0; wpa_drivers[i]; i++) {
239 if (wpa_drivers[i] != hapd->driver)
240 continue;
241
242 if (global.drv_priv[i] == NULL &&
243 wpa_drivers[i]->global_init) {
244 global.drv_priv[i] =
245 wpa_drivers[i]->global_init(iface->interfaces);
246 if (global.drv_priv[i] == NULL) {
247 wpa_printf(MSG_ERROR, "Failed to initialize "
248 "driver '%s'",
249 wpa_drivers[i]->name);
250 return -1;
251 }
252 }
253
254 params.global_priv = global.drv_priv[i];
255 break;
256 }
257 params.bssid = b;
258 params.ifname = hapd->conf->iface;
259 params.driver_params = hapd->iconf->driver_params;
260 params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
261
262 params.num_bridge = hapd->iface->num_bss;
263 params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
264 if (params.bridge == NULL)
265 return -1;
266 for (i = 0; i < hapd->iface->num_bss; i++) {
267 struct hostapd_data *bss = hapd->iface->bss[i];
268 if (bss->conf->bridge[0])
269 params.bridge[i] = bss->conf->bridge;
270 }
271
272 params.own_addr = hapd->own_addr;
273
274 hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
275 os_free(params.bridge);
276 if (hapd->drv_priv == NULL) {
277 wpa_printf(MSG_ERROR, "%s driver initialization failed.",
278 hapd->driver->name);
279 hapd->driver = NULL;
280 return -1;
281 }
282
283#ifdef CONFIG_IEEE80211BE
284 /*
285 * This is the first interface added to the AP MLD, so have the
286 * interface hardware address be the MLD address and set a link address
287 * to this interface.
288 */
289 if (hapd->conf->mld_ap) {
290 os_memcpy(hapd->mld_addr, hapd->own_addr, ETH_ALEN);
291 random_mac_addr_keep_oui(hapd->own_addr);
292 hapd->mld_next_link_id = 0;
293 hapd->mld_link_id = hapd->mld_next_link_id++;
294 }
295
296setup_mld:
297#endif /* CONFIG_IEEE80211BE */
298
299 if (hapd->driver->get_capa &&
300 hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
301 struct wowlan_triggers *triggs;
302
303 iface->drv_flags = capa.flags;
304 iface->drv_flags2 = capa.flags2;
305 iface->probe_resp_offloads = capa.probe_resp_offloads;
306 /*
307 * Use default extended capa values from per-radio information
308 */
309 iface->extended_capa = capa.extended_capa;
310 iface->extended_capa_mask = capa.extended_capa_mask;
311 iface->extended_capa_len = capa.extended_capa_len;
312 iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
313
314 /*
315 * Override extended capa with per-interface type (AP), if
316 * available from the driver.
317 */
318 hostapd_get_ext_capa(iface);
319
320 hostapd_get_mld_capa(iface);
321
322 triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
323 if (triggs && hapd->driver->set_wowlan) {
324 if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
325 wpa_printf(MSG_ERROR, "set_wowlan failed");
326 }
327 os_free(triggs);
328
329 iface->mbssid_max_interfaces = capa.mbssid_max_interfaces;
330 iface->ema_max_periodicity = capa.ema_max_periodicity;
331 }
332
333#ifdef CONFIG_IEEE80211BE
334 if (hapd->conf->mld_ap) {
335 if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) {
336 wpa_printf(MSG_INFO,
337 "MLD: Not supported by the driver");
338 return -1;
339 }
340
341 wpa_printf(MSG_DEBUG,
342 "MLD: Set link_id=%u, mld_addr=" MACSTR
343 ", own_addr=" MACSTR,
344 hapd->mld_link_id, MAC2STR(hapd->mld_addr),
345 MAC2STR(hapd->own_addr));
346
347 hostapd_drv_link_add(hapd, hapd->mld_link_id,
348 hapd->own_addr);
349 }
350#endif /* CONFIG_IEEE80211BE */
351
352 return 0;
353}
354
355
356/**
357 * hostapd_interface_init - Read configuration file and init BSS data
358 *
359 * This function is used to parse configuration file for a full interface (one
360 * or more BSSes sharing the same radio) and allocate memory for the BSS
361 * interfaces. No actual driver operations are started.
362 */
363static struct hostapd_iface *
364hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
365 const char *config_fname, int debug)
366{
367 struct hostapd_iface *iface;
368 int k;
369
370 wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
371 iface = hostapd_init(interfaces, config_fname);
372 if (!iface)
373 return NULL;
374
375 if (if_name) {
376 os_strlcpy(iface->conf->bss[0]->iface, if_name,
377 sizeof(iface->conf->bss[0]->iface));
378 }
379
380 iface->interfaces = interfaces;
381
382 for (k = 0; k < debug; k++) {
383 if (iface->bss[0]->conf->logger_stdout_level > 0)
384 iface->bss[0]->conf->logger_stdout_level--;
385 }
386
387 if (iface->conf->bss[0]->iface[0] == '\0' &&
388 !hostapd_drv_none(iface->bss[0])) {
389 wpa_printf(MSG_ERROR,
390 "Interface name not specified in %s, nor by '-i' parameter",
391 config_fname);
392 hostapd_interface_deinit_free(iface);
393 return NULL;
394 }
395
396 return iface;
397}
398
399
400/**
401 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
402 */
403static void handle_term(int sig, void *signal_ctx)
404{
405 wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
406 eloop_terminate();
407}
408
409
410#ifndef CONFIG_NATIVE_WINDOWS
411
412static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
413{
414 if (hostapd_reload_config(iface, 0) < 0) {
415 wpa_printf(MSG_WARNING, "Failed to read new configuration "
416 "file - continuing with old.");
417 }
418 return 0;
419}
420
421
422/**
423 * handle_reload - SIGHUP handler to reload configuration
424 */
425static void handle_reload(int sig, void *signal_ctx)
426{
427 struct hapd_interfaces *interfaces = signal_ctx;
428 wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
429 sig);
430 hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
431}
432
433
434static void handle_dump_state(int sig, void *signal_ctx)
435{
436 /* Not used anymore - ignore signal */
437}
438#endif /* CONFIG_NATIVE_WINDOWS */
439
440
441static int hostapd_global_init(struct hapd_interfaces *interfaces,
442 const char *entropy_file)
443{
444 int i;
445
446 os_memset(&global, 0, sizeof(global));
447
448 hostapd_logger_register_cb(hostapd_logger_cb);
449
450 if (eap_server_register_methods()) {
451 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
452 return -1;
453 }
454
455 if (eloop_init()) {
456 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
457 return -1;
458 }
459 interfaces->eloop_initialized = 1;
460
461 random_init(entropy_file);
462
463#ifndef CONFIG_NATIVE_WINDOWS
464 eloop_register_signal(SIGHUP, handle_reload, interfaces);
465 eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
466#endif /* CONFIG_NATIVE_WINDOWS */
467 eloop_register_signal_terminate(handle_term, interfaces);
468
469#ifndef CONFIG_NATIVE_WINDOWS
470 openlog("hostapd", 0, LOG_DAEMON);
471#endif /* CONFIG_NATIVE_WINDOWS */
472
473 for (i = 0; wpa_drivers[i]; i++)
474 global.drv_count++;
475 if (global.drv_count == 0) {
476 wpa_printf(MSG_ERROR, "No drivers enabled");
477 return -1;
478 }
479 global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
480 if (global.drv_priv == NULL)
481 return -1;
482
483 return 0;
484}
485
486
487static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
488{
489 int i;
490
491 for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
492 if (!global.drv_priv[i])
493 continue;
494 wpa_drivers[i]->global_deinit(global.drv_priv[i]);
495 }
496 os_free(global.drv_priv);
497 global.drv_priv = NULL;
498
499#ifdef EAP_SERVER_TNC
500 tncs_global_deinit();
501#endif /* EAP_SERVER_TNC */
502
503 random_deinit();
504
505 if (eloop_initialized)
506 eloop_destroy();
507
508#ifndef CONFIG_NATIVE_WINDOWS
509 closelog();
510#endif /* CONFIG_NATIVE_WINDOWS */
511
512 eap_server_unregister_methods();
513}
514
515
516static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
517 const char *pid_file)
518{
519#ifdef EAP_SERVER_TNC
520 int tnc = 0;
521 size_t i, k;
522
523 for (i = 0; !tnc && i < ifaces->count; i++) {
524 for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
525 if (ifaces->iface[i]->bss[0]->conf->tnc) {
526 tnc++;
527 break;
528 }
529 }
530 }
531
532 if (tnc && tncs_global_init() < 0) {
533 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
534 return -1;
535 }
536#endif /* EAP_SERVER_TNC */
537
538 eloop_run();
539
540 return 0;
541}
542
543
544static void show_version(void)
545{
546 fprintf(stderr,
547 "hostapd v%s\n"
548 "User space daemon for IEEE 802.11 AP management,\n"
549 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
550 "Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> "
551 "and contributors\n",
552 VERSION_STR);
553}
554
555
556static void usage(void)
557{
558 show_version();
559 fprintf(stderr,
560 "\n"
561 "usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] "
562 "\\\n"
563 " [-g <global ctrl_iface>] [-G <group>]\\\n"
564 " [-i <comma-separated list of interface names>]\\\n"
565 " <configuration file(s)>\n"
566 "\n"
567 "options:\n"
568 " -h show this usage\n"
569 " -d show more debug messages (-dd for even more)\n"
570 " -B run daemon in the background\n"
571 " -e entropy file\n"
572 " -g global control interface path\n"
573 " -G group for control interfaces\n"
574 " -P PID file\n"
575 " -K include key data in debug messages\n"
576#ifdef CONFIG_DEBUG_FILE
577 " -f log output to debug file instead of stdout\n"
578#endif /* CONFIG_DEBUG_FILE */
579#ifdef CONFIG_DEBUG_LINUX_TRACING
580 " -T record to Linux tracing in addition to logging\n"
581 " (records all messages regardless of debug verbosity)\n"
582#endif /* CONFIG_DEBUG_LINUX_TRACING */
583 " -i list of interface names to use\n"
584#ifdef CONFIG_DEBUG_SYSLOG
585 " -s log output to syslog instead of stdout\n"
586#endif /* CONFIG_DEBUG_SYSLOG */
587 " -S start all the interfaces synchronously\n"
588 " -t include timestamps in some debug messages\n"
589 " -v show hostapd version\n"
590 " -q show less debug messages (-qq for even less)\n");
591
592 exit(1);
593}
594
595
596static const char * hostapd_msg_ifname_cb(void *ctx)
597{
598 struct hostapd_data *hapd = ctx;
599 if (hapd && hapd->conf)
600 return hapd->conf->iface;
601 return NULL;
602}
603
604
605static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
606 const char *path)
607{
608#ifndef CONFIG_CTRL_IFACE_UDP
609 char *pos;
610#endif /* !CONFIG_CTRL_IFACE_UDP */
611
612 os_free(interfaces->global_iface_path);
613 interfaces->global_iface_path = os_strdup(path);
614 if (interfaces->global_iface_path == NULL)
615 return -1;
616
617#ifndef CONFIG_CTRL_IFACE_UDP
618 pos = os_strrchr(interfaces->global_iface_path, '/');
619 if (pos == NULL) {
620 wpa_printf(MSG_ERROR, "No '/' in the global control interface "
621 "file");
622 os_free(interfaces->global_iface_path);
623 interfaces->global_iface_path = NULL;
624 return -1;
625 }
626
627 *pos = '\0';
628 interfaces->global_iface_name = pos + 1;
629#endif /* !CONFIG_CTRL_IFACE_UDP */
630
631 return 0;
632}
633
634
635static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
636 const char *group)
637{
638#ifndef CONFIG_NATIVE_WINDOWS
639 struct group *grp;
640 grp = getgrnam(group);
641 if (grp == NULL) {
642 wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
643 return -1;
644 }
645 interfaces->ctrl_iface_group = grp->gr_gid;
646#endif /* CONFIG_NATIVE_WINDOWS */
647 return 0;
648}
649
650
651static int hostapd_get_interface_names(char ***if_names,
652 size_t *if_names_size,
653 char *arg)
654{
655 char *if_name, *tmp, **nnames;
656 size_t i;
657
658 if (!arg)
659 return -1;
660 if_name = strtok_r(arg, ",", &tmp);
661
662 while (if_name) {
663 nnames = os_realloc_array(*if_names, 1 + *if_names_size,
664 sizeof(char *));
665 if (!nnames)
666 goto fail;
667 *if_names = nnames;
668
669 (*if_names)[*if_names_size] = os_strdup(if_name);
670 if (!(*if_names)[*if_names_size])
671 goto fail;
672 (*if_names_size)++;
673 if_name = strtok_r(NULL, ",", &tmp);
674 }
675
676 return 0;
677
678fail:
679 for (i = 0; i < *if_names_size; i++)
680 os_free((*if_names)[i]);
681 os_free(*if_names);
682 *if_names = NULL;
683 *if_names_size = 0;
684 return -1;
685}
686
687void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
688 union wpa_event_data *data);
689
690void hostapd_wpa_event_global(void *ctx, enum wpa_event_type event,
691 union wpa_event_data *data);
692
693#ifdef CONFIG_WPS
694static int gen_uuid(const char *txt_addr)
695{
696 u8 addr[ETH_ALEN];
697 u8 uuid[UUID_LEN];
698 char buf[100];
699
700 if (hwaddr_aton(txt_addr, addr) < 0)
701 return -1;
702
703 uuid_gen_mac_addr(addr, uuid);
704 if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
705 return -1;
706
707 printf("%s\n", buf);
708
709 return 0;
710}
711#endif /* CONFIG_WPS */
712
713
714#ifndef HOSTAPD_CLEANUP_INTERVAL
715#define HOSTAPD_CLEANUP_INTERVAL 10
716#endif /* HOSTAPD_CLEANUP_INTERVAL */
717
718static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
719{
720 hostapd_periodic_iface(iface);
721 return 0;
722}
723
724
725/* Periodic cleanup tasks */
726static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
727{
728 struct hapd_interfaces *interfaces = eloop_ctx;
729
730 eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
731 hostapd_periodic, interfaces, NULL);
732 hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
733}
734
735
736int main(int argc, char *argv[])
737{
738 struct hapd_interfaces interfaces;
739 int ret = 1;
740 size_t i, j;
741 int c, debug = 0;
742 const char *log_file = NULL;
743 const char *entropy_file = NULL;
744 char **bss_config = NULL, **tmp_bss;
745 size_t num_bss_configs = 0;
746#ifdef CONFIG_DEBUG_LINUX_TRACING
747 int enable_trace_dbg = 0;
748#endif /* CONFIG_DEBUG_LINUX_TRACING */
749 int start_ifaces_in_sync = 0;
750 char **if_names = NULL;
751 size_t if_names_size = 0;
752#ifdef CONFIG_DPP
753 struct dpp_global_config dpp_conf;
754#endif /* CONFIG_DPP */
755
756 if (os_program_init())
757 return -1;
758
759#ifdef RADIUS_SERVER
760 if (strstr(argv[0], "radius"))
761 return radius_main(argc, argv);
762#endif
763
764 os_memset(&interfaces, 0, sizeof(interfaces));
765 interfaces.reload_config = hostapd_reload_config;
766 interfaces.config_read_cb = hostapd_config_read;
767 interfaces.for_each_interface = hostapd_for_each_interface;
768 interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
769 interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
770 interfaces.driver_init = hostapd_driver_init;
771 interfaces.global_iface_path = NULL;
772 interfaces.global_iface_name = NULL;
773 interfaces.global_ctrl_sock = -1;
774 dl_list_init(&interfaces.global_ctrl_dst);
775#ifdef CONFIG_ETH_P_OUI
776 dl_list_init(&interfaces.eth_p_oui);
777#endif /* CONFIG_ETH_P_OUI */
778#ifdef CONFIG_DPP
779 os_memset(&dpp_conf, 0, sizeof(dpp_conf));
780 dpp_conf.cb_ctx = &interfaces;
781#ifdef CONFIG_DPP2
782 dpp_conf.remove_bi = hostapd_dpp_remove_bi;
783#endif /* CONFIG_DPP2 */
784 interfaces.dpp = dpp_global_init(&dpp_conf);
785 if (!interfaces.dpp)
786 return -1;
787#endif /* CONFIG_DPP */
788
789 wpa_supplicant_event = hostapd_wpa_event;
790 wpa_supplicant_event_global = hostapd_wpa_event_global;
791 for (;;) {
792 c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:g:G:qv::");
793 if (c < 0)
794 break;
795 switch (c) {
796 case 'h':
797 usage();
798 break;
799 case 'd':
800 debug++;
801 if (wpa_debug_level > 0)
802 wpa_debug_level--;
803 break;
804 case 'B':
805 daemonize++;
806 break;
807 case 'e':
808 entropy_file = optarg;
809 break;
810 case 'f':
811 log_file = optarg;
812 break;
813 case 'K':
814 wpa_debug_show_keys++;
815 break;
816 case 'P':
817 os_free(pid_file);
818 pid_file = os_rel2abs_path(optarg);
819 break;
820 case 't':
821 wpa_debug_timestamp++;
822 break;
823#ifdef CONFIG_DEBUG_LINUX_TRACING
824 case 'T':
825 enable_trace_dbg = 1;
826 break;
827#endif /* CONFIG_DEBUG_LINUX_TRACING */
828 case 'v':
829 if (optarg)
830 exit(!has_feature(optarg));
831 show_version();
832 exit(1);
833 case 'g':
834 if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
835 return -1;
836 break;
837 case 'G':
838 if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
839 return -1;
840 break;
841 case 'b':
842 tmp_bss = os_realloc_array(bss_config,
843 num_bss_configs + 1,
844 sizeof(char *));
845 if (tmp_bss == NULL)
846 goto out;
847 bss_config = tmp_bss;
848 bss_config[num_bss_configs++] = optarg;
849 break;
850#ifdef CONFIG_DEBUG_SYSLOG
851 case 's':
852 wpa_debug_syslog = 1;
853 break;
854#endif /* CONFIG_DEBUG_SYSLOG */
855 case 'S':
856 start_ifaces_in_sync = 1;
857 break;
858#ifdef CONFIG_WPS
859 case 'u':
860 return gen_uuid(optarg);
861#endif /* CONFIG_WPS */
862 case 'i':
863 if (hostapd_get_interface_names(&if_names,
864 &if_names_size, optarg))
865 goto out;
866 break;
867 case 'q':
868 wpa_debug_level++;
869 break;
870 default:
871 usage();
872 break;
873 }
874 }
875
876 if (optind == argc && interfaces.global_iface_path == NULL &&
877 num_bss_configs == 0)
878 usage();
879
880 wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
881
882 if (log_file)
883 wpa_debug_open_file(log_file);
884 if (!log_file && !wpa_debug_syslog)
885 wpa_debug_setup_stdout();
886#ifdef CONFIG_DEBUG_SYSLOG
887 if (wpa_debug_syslog)
888 wpa_debug_open_syslog();
889#endif /* CONFIG_DEBUG_SYSLOG */
890#ifdef CONFIG_DEBUG_LINUX_TRACING
891 if (enable_trace_dbg) {
892 int tret = wpa_debug_open_linux_tracing();
893 if (tret) {
894 wpa_printf(MSG_ERROR, "Failed to enable trace logging");
895 return -1;
896 }
897 }
898#endif /* CONFIG_DEBUG_LINUX_TRACING */
899
900 interfaces.count = argc - optind;
901 if (interfaces.count || num_bss_configs) {
902 interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
903 sizeof(struct hostapd_iface *));
904 if (interfaces.iface == NULL) {
905 wpa_printf(MSG_ERROR, "malloc failed");
906 return -1;
907 }
908 }
909
910 if (hostapd_global_init(&interfaces, entropy_file)) {
911 wpa_printf(MSG_ERROR, "Failed to initialize global context");
912 return -1;
913 }
914
915 eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
916 hostapd_periodic, &interfaces, NULL);
917
918 if (fst_global_init()) {
919 wpa_printf(MSG_ERROR,
920 "Failed to initialize global FST context");
921 goto out;
922 }
923
924#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
925 if (!fst_global_add_ctrl(fst_ctrl_cli))
926 wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
927#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
928
929 /* Allocate and parse configuration for full interface files */
930 for (i = 0; i < interfaces.count; i++) {
931 char *if_name = NULL;
932
933 if (i < if_names_size)
934 if_name = if_names[i];
935
936 interfaces.iface[i] = hostapd_interface_init(&interfaces,
937 if_name,
938 argv[optind + i],
939 debug);
940 if (!interfaces.iface[i]) {
941 wpa_printf(MSG_ERROR, "Failed to initialize interface");
942 goto out;
943 }
944 if (start_ifaces_in_sync)
945 interfaces.iface[i]->need_to_start_in_sync = 1;
946 }
947
948 /* Allocate and parse configuration for per-BSS files */
949 for (i = 0; i < num_bss_configs; i++) {
950 struct hostapd_iface *iface;
951 char *fname;
952
953 wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
954 fname = os_strchr(bss_config[i], ':');
955 if (fname == NULL) {
956 wpa_printf(MSG_ERROR,
957 "Invalid BSS config identifier '%s'",
958 bss_config[i]);
959 goto out;
960 }
961 *fname++ = '\0';
962 iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
963 fname, debug);
964 if (iface == NULL)
965 goto out;
966 for (j = 0; j < interfaces.count; j++) {
967 if (interfaces.iface[j] == iface)
968 break;
969 }
970 if (j == interfaces.count) {
971 struct hostapd_iface **tmp;
972 tmp = os_realloc_array(interfaces.iface,
973 interfaces.count + 1,
974 sizeof(struct hostapd_iface *));
975 if (tmp == NULL) {
976 hostapd_interface_deinit_free(iface);
977 goto out;
978 }
979 interfaces.iface = tmp;
980 interfaces.iface[interfaces.count++] = iface;
981 }
982 }
983
984 /*
985 * Enable configured interfaces. Depending on channel configuration,
986 * this may complete full initialization before returning or use a
987 * callback mechanism to complete setup in case of operations like HT
988 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
989 * In such case, the interface will be enabled from eloop context within
990 * hostapd_global_run().
991 */
992 interfaces.terminate_on_error = interfaces.count;
993 for (i = 0; i < interfaces.count; i++) {
994 if (hostapd_driver_init(interfaces.iface[i]) ||
995 hostapd_setup_interface(interfaces.iface[i]))
996 goto out;
997 }
998
999 hostapd_global_ctrl_iface_init(&interfaces);
1000 hostapd_ubus_add(&interfaces);
1001
1002 if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
1003 wpa_printf(MSG_ERROR, "Failed to start eloop");
1004 goto out;
1005 }
1006
1007 ret = 0;
1008
1009 out:
1010 hostapd_ubus_free(&interfaces);
1011 hostapd_global_ctrl_iface_deinit(&interfaces);
1012 /* Deinitialize all interfaces */
1013 for (i = 0; i < interfaces.count; i++) {
1014 if (!interfaces.iface[i])
1015 continue;
1016 interfaces.iface[i]->driver_ap_teardown =
1017 !!(interfaces.iface[i]->drv_flags &
1018 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
1019 hostapd_interface_deinit_free(interfaces.iface[i]);
1020 interfaces.iface[i] = NULL;
1021 }
1022 os_free(interfaces.iface);
1023 interfaces.iface = NULL;
1024 interfaces.count = 0;
1025
1026#ifdef CONFIG_DPP
1027 dpp_global_deinit(interfaces.dpp);
1028#endif /* CONFIG_DPP */
1029
1030 if (interfaces.eloop_initialized)
1031 eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
1032 hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
1033 os_free(pid_file);
1034
1035 wpa_debug_close_syslog();
1036 if (log_file)
1037 wpa_debug_close_file();
1038 wpa_debug_close_linux_tracing();
1039
1040 os_free(bss_config);
1041
1042 for (i = 0; i < if_names_size; i++)
1043 os_free(if_names[i]);
1044 os_free(if_names);
1045
1046 fst_global_deinit();
1047
1048 crypto_unload();
1049 os_program_deinit();
1050
1051 return ret;
1052}