1b798dafc0427f9910934682e8e7f8f24ffe13ce
[mech_eap.git] / hostapd / main.c
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 #include <grp.h>
13 #endif /* CONFIG_NATIVE_WINDOWS */
14
15 #include "utils/common.h"
16 #include "utils/eloop.h"
17 #include "crypto/random.h"
18 #include "crypto/tls.h"
19 #include "common/version.h"
20 #include "drivers/driver.h"
21 #include "eap_server/eap.h"
22 #include "eap_server/tncs.h"
23 #include "ap/hostapd.h"
24 #include "ap/ap_config.h"
25 #include "ap/ap_drv_ops.h"
26 #include "config_file.h"
27 #include "eap_register.h"
28 #include "dump_state.h"
29 #include "ctrl_iface.h"
30
31
32 extern int wpa_debug_level;
33 extern int wpa_debug_show_keys;
34 extern int wpa_debug_timestamp;
35
36
37 struct hapd_global {
38         void **drv_priv;
39         size_t drv_count;
40 };
41
42 static struct hapd_global global;
43
44
45 #ifndef CONFIG_NO_HOSTAPD_LOGGER
46 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
47                               int level, const char *txt, size_t len)
48 {
49         struct hostapd_data *hapd = ctx;
50         char *format, *module_str;
51         int maxlen;
52         int conf_syslog_level, conf_stdout_level;
53         unsigned int conf_syslog, conf_stdout;
54
55         maxlen = len + 100;
56         format = os_malloc(maxlen);
57         if (!format)
58                 return;
59
60         if (hapd && hapd->conf) {
61                 conf_syslog_level = hapd->conf->logger_syslog_level;
62                 conf_stdout_level = hapd->conf->logger_stdout_level;
63                 conf_syslog = hapd->conf->logger_syslog;
64                 conf_stdout = hapd->conf->logger_stdout;
65         } else {
66                 conf_syslog_level = conf_stdout_level = 0;
67                 conf_syslog = conf_stdout = (unsigned int) -1;
68         }
69
70         switch (module) {
71         case HOSTAPD_MODULE_IEEE80211:
72                 module_str = "IEEE 802.11";
73                 break;
74         case HOSTAPD_MODULE_IEEE8021X:
75                 module_str = "IEEE 802.1X";
76                 break;
77         case HOSTAPD_MODULE_RADIUS:
78                 module_str = "RADIUS";
79                 break;
80         case HOSTAPD_MODULE_WPA:
81                 module_str = "WPA";
82                 break;
83         case HOSTAPD_MODULE_DRIVER:
84                 module_str = "DRIVER";
85                 break;
86         case HOSTAPD_MODULE_IAPP:
87                 module_str = "IAPP";
88                 break;
89         case HOSTAPD_MODULE_MLME:
90                 module_str = "MLME";
91                 break;
92         default:
93                 module_str = NULL;
94                 break;
95         }
96
97         if (hapd && hapd->conf && addr)
98                 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
99                             hapd->conf->iface, MAC2STR(addr),
100                             module_str ? " " : "", module_str, 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, txt);
105         else if (addr)
106                 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
107                             MAC2STR(addr), module_str ? " " : "",
108                             module_str, txt);
109         else
110                 os_snprintf(format, maxlen, "%s%s%s",
111                             module_str, module_str ? ": " : "", txt);
112
113         if ((conf_stdout & module) && level >= conf_stdout_level) {
114                 wpa_debug_print_timestamp();
115                 wpa_printf(MSG_INFO, "%s", format);
116         }
117
118 #ifndef CONFIG_NATIVE_WINDOWS
119         if ((conf_syslog & module) && level >= conf_syslog_level) {
120                 int priority;
121                 switch (level) {
122                 case HOSTAPD_LEVEL_DEBUG_VERBOSE:
123                 case HOSTAPD_LEVEL_DEBUG:
124                         priority = LOG_DEBUG;
125                         break;
126                 case HOSTAPD_LEVEL_INFO:
127                         priority = LOG_INFO;
128                         break;
129                 case HOSTAPD_LEVEL_NOTICE:
130                         priority = LOG_NOTICE;
131                         break;
132                 case HOSTAPD_LEVEL_WARNING:
133                         priority = LOG_WARNING;
134                         break;
135                 default:
136                         priority = LOG_INFO;
137                         break;
138                 }
139                 syslog(priority, "%s", format);
140         }
141 #endif /* CONFIG_NATIVE_WINDOWS */
142
143         os_free(format);
144 }
145 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
146
147
148 /**
149  * hostapd_driver_init - Preparate driver interface
150  */
151 static int hostapd_driver_init(struct hostapd_iface *iface)
152 {
153         struct wpa_init_params params;
154         size_t i;
155         struct hostapd_data *hapd = iface->bss[0];
156         struct hostapd_bss_config *conf = hapd->conf;
157         u8 *b = conf->bssid;
158         struct wpa_driver_capa capa;
159
160         if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
161                 wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
162                 return -1;
163         }
164
165         /* Initialize the driver interface */
166         if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
167                 b = NULL;
168
169         os_memset(&params, 0, sizeof(params));
170         for (i = 0; wpa_drivers[i]; i++) {
171                 if (wpa_drivers[i] != hapd->driver)
172                         continue;
173
174                 if (global.drv_priv[i] == NULL &&
175                     wpa_drivers[i]->global_init) {
176                         global.drv_priv[i] = wpa_drivers[i]->global_init();
177                         if (global.drv_priv[i] == NULL) {
178                                 wpa_printf(MSG_ERROR, "Failed to initialize "
179                                            "driver '%s'",
180                                            wpa_drivers[i]->name);
181                                 return -1;
182                         }
183                 }
184
185                 params.global_priv = global.drv_priv[i];
186                 break;
187         }
188         params.bssid = b;
189         params.ifname = hapd->conf->iface;
190         params.ssid = hapd->conf->ssid.ssid;
191         params.ssid_len = hapd->conf->ssid.ssid_len;
192         params.test_socket = hapd->conf->test_socket;
193         params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
194
195         params.num_bridge = hapd->iface->num_bss;
196         params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
197         if (params.bridge == NULL)
198                 return -1;
199         for (i = 0; i < hapd->iface->num_bss; i++) {
200                 struct hostapd_data *bss = hapd->iface->bss[i];
201                 if (bss->conf->bridge[0])
202                         params.bridge[i] = bss->conf->bridge;
203         }
204
205         params.own_addr = hapd->own_addr;
206
207         hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
208         os_free(params.bridge);
209         if (hapd->drv_priv == NULL) {
210                 wpa_printf(MSG_ERROR, "%s driver initialization failed.",
211                            hapd->driver->name);
212                 hapd->driver = NULL;
213                 return -1;
214         }
215
216         if (hapd->driver->get_capa &&
217             hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
218                 iface->drv_flags = capa.flags;
219                 iface->probe_resp_offloads = capa.probe_resp_offloads;
220                 iface->extended_capa = capa.extended_capa;
221                 iface->extended_capa_mask = capa.extended_capa_mask;
222                 iface->extended_capa_len = capa.extended_capa_len;
223                 iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
224         }
225
226         return 0;
227 }
228
229
230 /**
231  * hostapd_interface_init - Read configuration file and init BSS data
232  *
233  * This function is used to parse configuration file for a full interface (one
234  * or more BSSes sharing the same radio) and allocate memory for the BSS
235  * interfaces. No actiual driver operations are started.
236  */
237 static struct hostapd_iface *
238 hostapd_interface_init(struct hapd_interfaces *interfaces,
239                        const char *config_fname, int debug)
240 {
241         struct hostapd_iface *iface;
242         int k;
243
244         wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
245         iface = hostapd_init(interfaces, config_fname);
246         if (!iface)
247                 return NULL;
248         iface->interfaces = interfaces;
249
250         for (k = 0; k < debug; k++) {
251                 if (iface->bss[0]->conf->logger_stdout_level > 0)
252                         iface->bss[0]->conf->logger_stdout_level--;
253         }
254
255         if (iface->conf->bss[0]->iface[0] == '\0' &&
256             !hostapd_drv_none(iface->bss[0])) {
257                 wpa_printf(MSG_ERROR, "Interface name not specified in %s",
258                            config_fname);
259                 hostapd_interface_deinit_free(iface);
260                 return NULL;
261         }
262
263         return iface;
264 }
265
266
267 /**
268  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
269  */
270 static void handle_term(int sig, void *signal_ctx)
271 {
272         wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
273         eloop_terminate();
274 }
275
276
277 #ifndef CONFIG_NATIVE_WINDOWS
278
279 static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
280 {
281         if (hostapd_reload_config(iface) < 0) {
282                 wpa_printf(MSG_WARNING, "Failed to read new configuration "
283                            "file - continuing with old.");
284         }
285         return 0;
286 }
287
288
289 /**
290  * handle_reload - SIGHUP handler to reload configuration
291  */
292 static void handle_reload(int sig, void *signal_ctx)
293 {
294         struct hapd_interfaces *interfaces = signal_ctx;
295         wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
296                    sig);
297         hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
298 }
299
300
301 static void handle_dump_state(int sig, void *signal_ctx)
302 {
303 #ifdef HOSTAPD_DUMP_STATE
304         struct hapd_interfaces *interfaces = signal_ctx;
305         hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
306 #endif /* HOSTAPD_DUMP_STATE */
307 }
308 #endif /* CONFIG_NATIVE_WINDOWS */
309
310
311 static int hostapd_global_init(struct hapd_interfaces *interfaces,
312                                const char *entropy_file)
313 {
314         int i;
315
316         os_memset(&global, 0, sizeof(global));
317
318         hostapd_logger_register_cb(hostapd_logger_cb);
319
320         if (eap_server_register_methods()) {
321                 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
322                 return -1;
323         }
324
325         if (eloop_init()) {
326                 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
327                 return -1;
328         }
329
330         random_init(entropy_file);
331
332 #ifndef CONFIG_NATIVE_WINDOWS
333         eloop_register_signal(SIGHUP, handle_reload, interfaces);
334         eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
335 #endif /* CONFIG_NATIVE_WINDOWS */
336         eloop_register_signal_terminate(handle_term, interfaces);
337
338 #ifndef CONFIG_NATIVE_WINDOWS
339         openlog("hostapd", 0, LOG_DAEMON);
340 #endif /* CONFIG_NATIVE_WINDOWS */
341
342         for (i = 0; wpa_drivers[i]; i++)
343                 global.drv_count++;
344         if (global.drv_count == 0) {
345                 wpa_printf(MSG_ERROR, "No drivers enabled");
346                 return -1;
347         }
348         global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
349         if (global.drv_priv == NULL)
350                 return -1;
351
352         return 0;
353 }
354
355
356 static void hostapd_global_deinit(const char *pid_file)
357 {
358         int i;
359
360         for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
361                 if (!global.drv_priv[i])
362                         continue;
363                 wpa_drivers[i]->global_deinit(global.drv_priv[i]);
364         }
365         os_free(global.drv_priv);
366         global.drv_priv = NULL;
367
368 #ifdef EAP_SERVER_TNC
369         tncs_global_deinit();
370 #endif /* EAP_SERVER_TNC */
371
372         random_deinit();
373
374         eloop_destroy();
375
376 #ifndef CONFIG_NATIVE_WINDOWS
377         closelog();
378 #endif /* CONFIG_NATIVE_WINDOWS */
379
380         eap_server_unregister_methods();
381
382         os_daemonize_terminate(pid_file);
383 }
384
385
386 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
387                               const char *pid_file)
388 {
389 #ifdef EAP_SERVER_TNC
390         int tnc = 0;
391         size_t i, k;
392
393         for (i = 0; !tnc && i < ifaces->count; i++) {
394                 for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
395                         if (ifaces->iface[i]->bss[0]->conf->tnc) {
396                                 tnc++;
397                                 break;
398                         }
399                 }
400         }
401
402         if (tnc && tncs_global_init() < 0) {
403                 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
404                 return -1;
405         }
406 #endif /* EAP_SERVER_TNC */
407
408         if (daemonize && os_daemonize(pid_file)) {
409                 perror("daemon");
410                 return -1;
411         }
412
413         eloop_run();
414
415         return 0;
416 }
417
418
419 static void show_version(void)
420 {
421         fprintf(stderr,
422                 "hostapd v" VERSION_STR "\n"
423                 "User space daemon for IEEE 802.11 AP management,\n"
424                 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
425                 "Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> "
426                 "and contributors\n");
427 }
428
429
430 static void usage(void)
431 {
432         show_version();
433         fprintf(stderr,
434                 "\n"
435                 "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
436                 "\\\n"
437                 "         [-g <global ctrl_iface>] [-G <group>] \\\n"
438                 "         <configuration file(s)>\n"
439                 "\n"
440                 "options:\n"
441                 "   -h   show this usage\n"
442                 "   -d   show more debug messages (-dd for even more)\n"
443                 "   -B   run daemon in the background\n"
444                 "   -e   entropy file\n"
445                 "   -g   global control interface path\n"
446                 "   -G   group for control interfaces\n"
447                 "   -P   PID file\n"
448                 "   -K   include key data in debug messages\n"
449 #ifdef CONFIG_DEBUG_FILE
450                 "   -f   log output to debug file instead of stdout\n"
451 #endif /* CONFIG_DEBUG_FILE */
452 #ifdef CONFIG_DEBUG_LINUX_TRACING
453                 "   -T = record to Linux tracing in addition to logging\n"
454                 "        (records all messages regardless of debug verbosity)\n"
455 #endif /* CONFIG_DEBUG_LINUX_TRACING */
456                 "   -t   include timestamps in some debug messages\n"
457                 "   -v   show hostapd version\n");
458
459         exit(1);
460 }
461
462
463 static const char * hostapd_msg_ifname_cb(void *ctx)
464 {
465         struct hostapd_data *hapd = ctx;
466         if (hapd && hapd->iconf && hapd->iconf->bss &&
467             hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
468                 return hapd->iconf->bss[0]->iface;
469         return NULL;
470 }
471
472
473 static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
474                                          const char *path)
475 {
476         char *pos;
477         os_free(interfaces->global_iface_path);
478         interfaces->global_iface_path = os_strdup(path);
479         if (interfaces->global_iface_path == NULL)
480                 return -1;
481         pos = os_strrchr(interfaces->global_iface_path, '/');
482         if (pos == NULL) {
483                 wpa_printf(MSG_ERROR, "No '/' in the global control interface "
484                            "file");
485                 os_free(interfaces->global_iface_path);
486                 interfaces->global_iface_path = NULL;
487                 return -1;
488         }
489
490         *pos = '\0';
491         interfaces->global_iface_name = pos + 1;
492
493         return 0;
494 }
495
496
497 static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
498                                         const char *group)
499 {
500 #ifndef CONFIG_NATIVE_WINDOWS
501         struct group *grp;
502         grp = getgrnam(group);
503         if (grp == NULL) {
504                 wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
505                 return -1;
506         }
507         interfaces->ctrl_iface_group = grp->gr_gid;
508 #endif /* CONFIG_NATIVE_WINDOWS */
509         return 0;
510 }
511
512
513 int main(int argc, char *argv[])
514 {
515         struct hapd_interfaces interfaces;
516         int ret = 1;
517         size_t i, j;
518         int c, debug = 0, daemonize = 0;
519         char *pid_file = NULL;
520         const char *log_file = NULL;
521         const char *entropy_file = NULL;
522         char **bss_config = NULL, **tmp_bss;
523         size_t num_bss_configs = 0;
524 #ifdef CONFIG_DEBUG_LINUX_TRACING
525         int enable_trace_dbg = 0;
526 #endif /* CONFIG_DEBUG_LINUX_TRACING */
527
528         if (os_program_init())
529                 return -1;
530
531         os_memset(&interfaces, 0, sizeof(interfaces));
532         interfaces.reload_config = hostapd_reload_config;
533         interfaces.config_read_cb = hostapd_config_read;
534         interfaces.for_each_interface = hostapd_for_each_interface;
535         interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
536         interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
537         interfaces.driver_init = hostapd_driver_init;
538         interfaces.global_iface_path = NULL;
539         interfaces.global_iface_name = NULL;
540         interfaces.global_ctrl_sock = -1;
541
542         for (;;) {
543                 c = getopt(argc, argv, "b:Bde:f:hKP:Ttvg:G:");
544                 if (c < 0)
545                         break;
546                 switch (c) {
547                 case 'h':
548                         usage();
549                         break;
550                 case 'd':
551                         debug++;
552                         if (wpa_debug_level > 0)
553                                 wpa_debug_level--;
554                         break;
555                 case 'B':
556                         daemonize++;
557                         break;
558                 case 'e':
559                         entropy_file = optarg;
560                         break;
561                 case 'f':
562                         log_file = optarg;
563                         break;
564                 case 'K':
565                         wpa_debug_show_keys++;
566                         break;
567                 case 'P':
568                         os_free(pid_file);
569                         pid_file = os_rel2abs_path(optarg);
570                         break;
571                 case 't':
572                         wpa_debug_timestamp++;
573                         break;
574 #ifdef CONFIG_DEBUG_LINUX_TRACING
575                 case 'T':
576                         enable_trace_dbg = 1;
577                         break;
578 #endif /* CONFIG_DEBUG_LINUX_TRACING */
579                 case 'v':
580                         show_version();
581                         exit(1);
582                         break;
583                 case 'g':
584                         if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
585                                 return -1;
586                         break;
587                 case 'G':
588                         if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
589                                 return -1;
590                         break;
591                 case 'b':
592                         tmp_bss = os_realloc_array(bss_config,
593                                                    num_bss_configs + 1,
594                                                    sizeof(char *));
595                         if (tmp_bss == NULL)
596                                 goto out;
597                         bss_config = tmp_bss;
598                         bss_config[num_bss_configs++] = optarg;
599                         break;
600                 default:
601                         usage();
602                         break;
603                 }
604         }
605
606         if (optind == argc && interfaces.global_iface_path == NULL &&
607             num_bss_configs == 0)
608                 usage();
609
610         wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
611
612         if (log_file)
613                 wpa_debug_open_file(log_file);
614 #ifdef CONFIG_DEBUG_LINUX_TRACING
615         if (enable_trace_dbg) {
616                 int tret = wpa_debug_open_linux_tracing();
617                 if (tret) {
618                         wpa_printf(MSG_ERROR, "Failed to enable trace logging");
619                         return -1;
620                 }
621         }
622 #endif /* CONFIG_DEBUG_LINUX_TRACING */
623
624         interfaces.count = argc - optind;
625         if (interfaces.count || num_bss_configs) {
626                 interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
627                                              sizeof(struct hostapd_iface *));
628                 if (interfaces.iface == NULL) {
629                         wpa_printf(MSG_ERROR, "malloc failed");
630                         return -1;
631                 }
632         }
633
634         if (hostapd_global_init(&interfaces, entropy_file)) {
635                 wpa_printf(MSG_ERROR, "Failed to initilize global context");
636                 return -1;
637         }
638
639         /* Allocate and parse configuration for full interface files */
640         for (i = 0; i < interfaces.count; i++) {
641                 interfaces.iface[i] = hostapd_interface_init(&interfaces,
642                                                              argv[optind + i],
643                                                              debug);
644                 if (!interfaces.iface[i]) {
645                         wpa_printf(MSG_ERROR, "Failed to initialize interface");
646                         goto out;
647                 }
648         }
649
650         /* Allocate and parse configuration for per-BSS files */
651         for (i = 0; i < num_bss_configs; i++) {
652                 struct hostapd_iface *iface;
653                 char *fname;
654
655                 wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
656                 fname = os_strchr(bss_config[i], ':');
657                 if (fname == NULL) {
658                         wpa_printf(MSG_ERROR,
659                                    "Invalid BSS config identifier '%s'",
660                                    bss_config[i]);
661                         goto out;
662                 }
663                 *fname++ = '\0';
664                 iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
665                                                    fname, debug);
666                 if (iface == NULL)
667                         goto out;
668                 for (j = 0; j < interfaces.count; j++) {
669                         if (interfaces.iface[j] == iface)
670                                 break;
671                 }
672                 if (j == interfaces.count) {
673                         struct hostapd_iface **tmp;
674                         tmp = os_realloc_array(interfaces.iface,
675                                                interfaces.count + 1,
676                                                sizeof(struct hostapd_iface *));
677                         if (tmp == NULL) {
678                                 hostapd_interface_deinit_free(iface);
679                                 goto out;
680                         }
681                         interfaces.iface = tmp;
682                         interfaces.iface[interfaces.count++] = iface;
683                 }
684         }
685
686         /*
687          * Enable configured interfaces. Depending on channel configuration,
688          * this may complete full initialization before returning or use a
689          * callback mechanism to complete setup in case of operations like HT
690          * co-ex scans, ACS, or DFS are needed to determine channel parameters.
691          * In such case, the interface will be enabled from eloop context within
692          * hostapd_global_run().
693          */
694         interfaces.terminate_on_error = interfaces.count;
695         for (i = 0; i < interfaces.count; i++) {
696                 if (hostapd_driver_init(interfaces.iface[i]) ||
697                     hostapd_setup_interface(interfaces.iface[i]))
698                         goto out;
699         }
700
701         hostapd_global_ctrl_iface_init(&interfaces);
702
703         if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
704                 wpa_printf(MSG_ERROR, "Failed to start eloop");
705                 goto out;
706         }
707
708         ret = 0;
709
710  out:
711         hostapd_global_ctrl_iface_deinit(&interfaces);
712         /* Deinitialize all interfaces */
713         for (i = 0; i < interfaces.count; i++)
714                 hostapd_interface_deinit_free(interfaces.iface[i]);
715         os_free(interfaces.iface);
716
717         hostapd_global_deinit(pid_file);
718         os_free(pid_file);
719
720         if (log_file)
721                 wpa_debug_close_file();
722         wpa_debug_close_linux_tracing();
723
724         os_free(bss_config);
725
726         os_program_deinit();
727
728         return ret;
729 }