1 /* 2 * hostapd / main() 3 * Copyright (c) 2002-2011, Jouni Malinen <j (at) 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 "utils/includes.h" 16 #ifndef CONFIG_NATIVE_WINDOWS 17 #include <syslog.h> 18 #endif /* CONFIG_NATIVE_WINDOWS */ 19 20 #include "utils/common.h" 21 #include "utils/eloop.h" 22 #include "crypto/random.h" 23 #include "crypto/tls.h" 24 #include "common/version.h" 25 #include "drivers/driver.h" 26 #include "eap_server/eap.h" 27 #include "eap_server/tncs.h" 28 #include "ap/hostapd.h" 29 #include "ap/ap_config.h" 30 #include "config_file.h" 31 #include "eap_register.h" 32 #include "dump_state.h" 33 #include "ctrl_iface.h" 34 35 36 extern int wpa_debug_level; 37 extern int wpa_debug_show_keys; 38 extern int wpa_debug_timestamp; 39 40 41 struct hapd_interfaces { 42 size_t count; 43 struct hostapd_iface **iface; 44 }; 45 46 47 static int hostapd_for_each_interface(struct hapd_interfaces *interfaces, 48 int (*cb)(struct hostapd_iface *iface, 49 void *ctx), void *ctx) 50 { 51 size_t i; 52 int ret; 53 54 for (i = 0; i < interfaces->count; i++) { 55 ret = cb(interfaces->iface[i], ctx); 56 if (ret) 57 return ret; 58 } 59 60 return 0; 61 } 62 63 64 #ifndef CONFIG_NO_HOSTAPD_LOGGER 65 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, 66 int level, const char *txt, size_t len) 67 { 68 struct hostapd_data *hapd = ctx; 69 char *format, *module_str; 70 int maxlen; 71 int conf_syslog_level, conf_stdout_level; 72 unsigned int conf_syslog, conf_stdout; 73 74 maxlen = len + 100; 75 format = os_malloc(maxlen); 76 if (!format) 77 return; 78 79 if (hapd && hapd->conf) { 80 conf_syslog_level = hapd->conf->logger_syslog_level; 81 conf_stdout_level = hapd->conf->logger_stdout_level; 82 conf_syslog = hapd->conf->logger_syslog; 83 conf_stdout = hapd->conf->logger_stdout; 84 } else { 85 conf_syslog_level = conf_stdout_level = 0; 86 conf_syslog = conf_stdout = (unsigned int) -1; 87 } 88 89 switch (module) { 90 case HOSTAPD_MODULE_IEEE80211: 91 module_str = "IEEE 802.11"; 92 break; 93 case HOSTAPD_MODULE_IEEE8021X: 94 module_str = "IEEE 802.1X"; 95 break; 96 case HOSTAPD_MODULE_RADIUS: 97 module_str = "RADIUS"; 98 break; 99 case HOSTAPD_MODULE_WPA: 100 module_str = "WPA"; 101 break; 102 case HOSTAPD_MODULE_DRIVER: 103 module_str = "DRIVER"; 104 break; 105 case HOSTAPD_MODULE_IAPP: 106 module_str = "IAPP"; 107 break; 108 case HOSTAPD_MODULE_MLME: 109 module_str = "MLME"; 110 break; 111 default: 112 module_str = NULL; 113 break; 114 } 115 116 if (hapd && hapd->conf && addr) 117 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", 118 hapd->conf->iface, MAC2STR(addr), 119 module_str ? " " : "", module_str, txt); 120 else if (hapd && hapd->conf) 121 os_snprintf(format, maxlen, "%s:%s%s %s", 122 hapd->conf->iface, module_str ? " " : "", 123 module_str, txt); 124 else if (addr) 125 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", 126 MAC2STR(addr), module_str ? " " : "", 127 module_str, txt); 128 else 129 os_snprintf(format, maxlen, "%s%s%s", 130 module_str, module_str ? ": " : "", txt); 131 132 if ((conf_stdout & module) && level >= conf_stdout_level) { 133 wpa_debug_print_timestamp(); 134 printf("%s\n", format); 135 } 136 137 #ifndef CONFIG_NATIVE_WINDOWS 138 if ((conf_syslog & module) && level >= conf_syslog_level) { 139 int priority; 140 switch (level) { 141 case HOSTAPD_LEVEL_DEBUG_VERBOSE: 142 case HOSTAPD_LEVEL_DEBUG: 143 priority = LOG_DEBUG; 144 break; 145 case HOSTAPD_LEVEL_INFO: 146 priority = LOG_INFO; 147 break; 148 case HOSTAPD_LEVEL_NOTICE: 149 priority = LOG_NOTICE; 150 break; 151 case HOSTAPD_LEVEL_WARNING: 152 priority = LOG_WARNING; 153 break; 154 default: 155 priority = LOG_INFO; 156 break; 157 } 158 syslog(priority, "%s", format); 159 } 160 #endif /* CONFIG_NATIVE_WINDOWS */ 161 162 os_free(format); 163 } 164 #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 165 166 167 /** 168 * hostapd_init - Allocate and initialize per-interface data 169 * @config_file: Path to the configuration file 170 * Returns: Pointer to the allocated interface data or %NULL on failure 171 * 172 * This function is used to allocate main data structures for per-interface 173 * data. The allocated data buffer will be freed by calling 174 * hostapd_cleanup_iface(). 175 */ 176 static struct hostapd_iface * hostapd_init(const char *config_file) 177 { 178 struct hostapd_iface *hapd_iface = NULL; 179 struct hostapd_config *conf = NULL; 180 struct hostapd_data *hapd; 181 size_t i; 182 183 hapd_iface = os_zalloc(sizeof(*hapd_iface)); 184 if (hapd_iface == NULL) 185 goto fail; 186 187 hapd_iface->reload_config = hostapd_reload_config; 188 hapd_iface->config_read_cb = hostapd_config_read; 189 hapd_iface->config_fname = os_strdup(config_file); 190 if (hapd_iface->config_fname == NULL) 191 goto fail; 192 hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init; 193 hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit; 194 hapd_iface->for_each_interface = hostapd_for_each_interface; 195 196 conf = hostapd_config_read(hapd_iface->config_fname); 197 if (conf == NULL) 198 goto fail; 199 hapd_iface->conf = conf; 200 201 hapd_iface->num_bss = conf->num_bss; 202 hapd_iface->bss = os_zalloc(conf->num_bss * 203 sizeof(struct hostapd_data *)); 204 if (hapd_iface->bss == NULL) 205 goto fail; 206 207 for (i = 0; i < conf->num_bss; i++) { 208 hapd = hapd_iface->bss[i] = 209 hostapd_alloc_bss_data(hapd_iface, conf, 210 &conf->bss[i]); 211 if (hapd == NULL) 212 goto fail; 213 hapd->msg_ctx = hapd; 214 } 215 216 return hapd_iface; 217 218 fail: 219 if (conf) 220 hostapd_config_free(conf); 221 if (hapd_iface) { 222 os_free(hapd_iface->config_fname); 223 os_free(hapd_iface->bss); 224 os_free(hapd_iface); 225 } 226 return NULL; 227 } 228 229 230 static int hostapd_driver_init(struct hostapd_iface *iface) 231 { 232 struct wpa_init_params params; 233 size_t i; 234 struct hostapd_data *hapd = iface->bss[0]; 235 struct hostapd_bss_config *conf = hapd->conf; 236 u8 *b = conf->bssid; 237 struct wpa_driver_capa capa; 238 239 if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { 240 wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); 241 return -1; 242 } 243 244 /* Initialize the driver interface */ 245 if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) 246 b = NULL; 247 248 os_memset(¶ms, 0, sizeof(params)); 249 params.bssid = b; 250 params.ifname = hapd->conf->iface; 251 params.ssid = (const u8 *) hapd->conf->ssid.ssid; 252 params.ssid_len = hapd->conf->ssid.ssid_len; 253 params.test_socket = hapd->conf->test_socket; 254 params.use_pae_group_addr = hapd->conf->use_pae_group_addr; 255 256 params.num_bridge = hapd->iface->num_bss; 257 params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *)); 258 if (params.bridge == NULL) 259 return -1; 260 for (i = 0; i < hapd->iface->num_bss; i++) { 261 struct hostapd_data *bss = hapd->iface->bss[i]; 262 if (bss->conf->bridge[0]) 263 params.bridge[i] = bss->conf->bridge; 264 } 265 266 params.own_addr = hapd->own_addr; 267 268 hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); 269 os_free(params.bridge); 270 if (hapd->drv_priv == NULL) { 271 wpa_printf(MSG_ERROR, "%s driver initialization failed.", 272 hapd->driver->name); 273 hapd->driver = NULL; 274 return -1; 275 } 276 277 if (hapd->driver->get_capa && 278 hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) 279 iface->drv_flags = capa.flags; 280 281 return 0; 282 } 283 284 285 static void hostapd_interface_deinit_free(struct hostapd_iface *iface) 286 { 287 const struct wpa_driver_ops *driver; 288 void *drv_priv; 289 if (iface == NULL) 290 return; 291 driver = iface->bss[0]->driver; 292 drv_priv = iface->bss[0]->drv_priv; 293 hostapd_interface_deinit(iface); 294 if (driver && driver->hapd_deinit) 295 driver->hapd_deinit(drv_priv); 296 hostapd_interface_free(iface); 297 } 298 299 300 static struct hostapd_iface * 301 hostapd_interface_init(struct hapd_interfaces *interfaces, 302 const char *config_fname, int debug) 303 { 304 struct hostapd_iface *iface; 305 int k; 306 307 wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); 308 iface = hostapd_init(config_fname); 309 if (!iface) 310 return NULL; 311 iface->interfaces = interfaces; 312 313 for (k = 0; k < debug; k++) { 314 if (iface->bss[0]->conf->logger_stdout_level > 0) 315 iface->bss[0]->conf->logger_stdout_level--; 316 } 317 318 if (hostapd_driver_init(iface) || 319 hostapd_setup_interface(iface)) { 320 hostapd_interface_deinit_free(iface); 321 return NULL; 322 } 323 324 return iface; 325 } 326 327 328 /** 329 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process 330 */ 331 static void handle_term(int sig, void *signal_ctx) 332 { 333 wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); 334 eloop_terminate(); 335 } 336 337 338 #ifndef CONFIG_NATIVE_WINDOWS 339 340 static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) 341 { 342 if (hostapd_reload_config(iface) < 0) { 343 wpa_printf(MSG_WARNING, "Failed to read new configuration " 344 "file - continuing with old."); 345 } 346 return 0; 347 } 348 349 350 /** 351 * handle_reload - SIGHUP handler to reload configuration 352 */ 353 static void handle_reload(int sig, void *signal_ctx) 354 { 355 struct hapd_interfaces *interfaces = signal_ctx; 356 wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", 357 sig); 358 hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); 359 } 360 361 362 static void handle_dump_state(int sig, void *signal_ctx) 363 { 364 #ifdef HOSTAPD_DUMP_STATE 365 struct hapd_interfaces *interfaces = signal_ctx; 366 hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); 367 #endif /* HOSTAPD_DUMP_STATE */ 368 } 369 #endif /* CONFIG_NATIVE_WINDOWS */ 370 371 372 static int hostapd_global_init(struct hapd_interfaces *interfaces, 373 const char *entropy_file) 374 { 375 hostapd_logger_register_cb(hostapd_logger_cb); 376 377 if (eap_server_register_methods()) { 378 wpa_printf(MSG_ERROR, "Failed to register EAP methods"); 379 return -1; 380 } 381 382 if (eloop_init()) { 383 wpa_printf(MSG_ERROR, "Failed to initialize event loop"); 384 return -1; 385 } 386 387 random_init(entropy_file); 388 389 #ifndef CONFIG_NATIVE_WINDOWS 390 eloop_register_signal(SIGHUP, handle_reload, interfaces); 391 eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); 392 #endif /* CONFIG_NATIVE_WINDOWS */ 393 eloop_register_signal_terminate(handle_term, interfaces); 394 395 #ifndef CONFIG_NATIVE_WINDOWS 396 openlog("hostapd", 0, LOG_DAEMON); 397 #endif /* CONFIG_NATIVE_WINDOWS */ 398 399 return 0; 400 } 401 402 403 static void hostapd_global_deinit(const char *pid_file) 404 { 405 #ifdef EAP_SERVER_TNC 406 tncs_global_deinit(); 407 #endif /* EAP_SERVER_TNC */ 408 409 random_deinit(); 410 411 eloop_destroy(); 412 413 #ifndef CONFIG_NATIVE_WINDOWS 414 closelog(); 415 #endif /* CONFIG_NATIVE_WINDOWS */ 416 417 eap_server_unregister_methods(); 418 419 os_daemonize_terminate(pid_file); 420 } 421 422 423 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, 424 const char *pid_file) 425 { 426 #ifdef EAP_SERVER_TNC 427 int tnc = 0; 428 size_t i, k; 429 430 for (i = 0; !tnc && i < ifaces->count; i++) { 431 for (k = 0; k < ifaces->iface[i]->num_bss; k++) { 432 if (ifaces->iface[i]->bss[0]->conf->tnc) { 433 tnc++; 434 break; 435 } 436 } 437 } 438 439 if (tnc && tncs_global_init() < 0) { 440 wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); 441 return -1; 442 } 443 #endif /* EAP_SERVER_TNC */ 444 445 if (daemonize && os_daemonize(pid_file)) { 446 perror("daemon"); 447 return -1; 448 } 449 450 eloop_run(); 451 452 return 0; 453 } 454 455 456 static void show_version(void) 457 { 458 fprintf(stderr, 459 "hostapd v" VERSION_STR "\n" 460 "User space daemon for IEEE 802.11 AP management,\n" 461 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" 462 "Copyright (c) 2002-2011, Jouni Malinen <j (at) w1.fi> " 463 "and contributors\n"); 464 } 465 466 467 static void usage(void) 468 { 469 show_version(); 470 fprintf(stderr, 471 "\n" 472 "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] " 473 "<configuration file(s)>\n" 474 "\n" 475 "options:\n" 476 " -h show this usage\n" 477 " -d show more debug messages (-dd for even more)\n" 478 " -B run daemon in the background\n" 479 " -e entropy file\n" 480 " -P PID file\n" 481 " -K include key data in debug messages\n" 482 #ifdef CONFIG_DEBUG_FILE 483 " -f log output to debug file instead of stdout\n" 484 #endif /* CONFIG_DEBUG_FILE */ 485 " -t include timestamps in some debug messages\n" 486 " -v show hostapd version\n"); 487 488 exit(1); 489 } 490 491 492 static const char * hostapd_msg_ifname_cb(void *ctx) 493 { 494 struct hostapd_data *hapd = ctx; 495 if (hapd && hapd->iconf && hapd->iconf->bss) 496 return hapd->iconf->bss->iface; 497 return NULL; 498 } 499 500 501 int main(int argc, char *argv[]) 502 { 503 struct hapd_interfaces interfaces; 504 int ret = 1; 505 size_t i; 506 int c, debug = 0, daemonize = 0; 507 char *pid_file = NULL; 508 const char *log_file = NULL; 509 const char *entropy_file = NULL; 510 511 if (os_program_init()) 512 return -1; 513 514 for (;;) { 515 c = getopt(argc, argv, "Bde:f:hKP:tv"); 516 if (c < 0) 517 break; 518 switch (c) { 519 case 'h': 520 usage(); 521 break; 522 case 'd': 523 debug++; 524 if (wpa_debug_level > 0) 525 wpa_debug_level--; 526 break; 527 case 'B': 528 daemonize++; 529 break; 530 case 'e': 531 entropy_file = optarg; 532 break; 533 case 'f': 534 log_file = optarg; 535 break; 536 case 'K': 537 wpa_debug_show_keys++; 538 break; 539 case 'P': 540 os_free(pid_file); 541 pid_file = os_rel2abs_path(optarg); 542 break; 543 case 't': 544 wpa_debug_timestamp++; 545 break; 546 case 'v': 547 show_version(); 548 exit(1); 549 break; 550 551 default: 552 usage(); 553 break; 554 } 555 } 556 557 if (optind == argc) 558 usage(); 559 560 wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); 561 562 if (log_file) 563 wpa_debug_open_file(log_file); 564 565 interfaces.count = argc - optind; 566 interfaces.iface = os_zalloc(interfaces.count * 567 sizeof(struct hostapd_iface *)); 568 if (interfaces.iface == NULL) { 569 wpa_printf(MSG_ERROR, "malloc failed"); 570 return -1; 571 } 572 573 if (hostapd_global_init(&interfaces, entropy_file)) 574 return -1; 575 576 /* Initialize interfaces */ 577 for (i = 0; i < interfaces.count; i++) { 578 interfaces.iface[i] = hostapd_interface_init(&interfaces, 579 argv[optind + i], 580 debug); 581 if (!interfaces.iface[i]) 582 goto out; 583 } 584 585 if (hostapd_global_run(&interfaces, daemonize, pid_file)) 586 goto out; 587 588 ret = 0; 589 590 out: 591 /* Deinitialize all interfaces */ 592 for (i = 0; i < interfaces.count; i++) 593 hostapd_interface_deinit_free(interfaces.iface[i]); 594 os_free(interfaces.iface); 595 596 hostapd_global_deinit(pid_file); 597 os_free(pid_file); 598 599 if (log_file) 600 wpa_debug_close_file(); 601 602 os_program_deinit(); 603 604 return ret; 605 } 606