diff options
Diffstat (limited to 'contrib/wpa/hostapd/main.c')
-rw-r--r-- | contrib/wpa/hostapd/main.c | 311 |
1 files changed, 209 insertions, 102 deletions
diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c index 56f0002..dd389a8 100644 --- a/contrib/wpa/hostapd/main.c +++ b/contrib/wpa/hostapd/main.c @@ -1,6 +1,6 @@ /* * hostapd / main() - * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,10 +9,12 @@ #include "utils/includes.h" #ifndef CONFIG_NATIVE_WINDOWS #include <syslog.h> +#include <grp.h> #endif /* CONFIG_NATIVE_WINDOWS */ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/uuid.h" #include "crypto/random.h" #include "crypto/tls.h" #include "common/version.h" @@ -24,17 +26,9 @@ #include "ap/ap_drv_ops.h" #include "config_file.h" #include "eap_register.h" -#include "dump_state.h" #include "ctrl_iface.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -extern struct wpa_driver_ops *wpa_drivers[]; - - struct hapd_global { void **drv_priv; size_t drv_count; @@ -98,22 +92,24 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, if (hapd && hapd->conf && addr) os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", hapd->conf->iface, MAC2STR(addr), - module_str ? " " : "", module_str, txt); + module_str ? " " : "", module_str ? module_str : "", + txt); else if (hapd && hapd->conf) os_snprintf(format, maxlen, "%s:%s%s %s", hapd->conf->iface, module_str ? " " : "", - module_str, txt); + module_str ? module_str : "", txt); else if (addr) os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", MAC2STR(addr), module_str ? " " : "", - module_str, txt); + module_str ? module_str : "", txt); else os_snprintf(format, maxlen, "%s%s%s", - module_str, module_str ? ": " : "", txt); + module_str ? module_str : "", + module_str ? ": " : "", txt); if ((conf_stdout & module) && level >= conf_stdout_level) { wpa_debug_print_timestamp(); - printf("%s\n", format); + wpa_printf(MSG_INFO, "%s", format); } #ifndef CONFIG_NATIVE_WINDOWS @@ -147,63 +143,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, /** - * hostapd_init - Allocate and initialize per-interface data - * @config_file: Path to the configuration file - * Returns: Pointer to the allocated interface data or %NULL on failure - * - * This function is used to allocate main data structures for per-interface - * data. The allocated data buffer will be freed by calling - * hostapd_cleanup_iface(). + * hostapd_driver_init - Preparate driver interface */ -static struct hostapd_iface * hostapd_init(const char *config_file) -{ - struct hostapd_iface *hapd_iface = NULL; - struct hostapd_config *conf = NULL; - struct hostapd_data *hapd; - size_t i; - - hapd_iface = os_zalloc(sizeof(*hapd_iface)); - if (hapd_iface == NULL) - goto fail; - - hapd_iface->config_fname = os_strdup(config_file); - if (hapd_iface->config_fname == NULL) - goto fail; - - conf = hostapd_config_read(hapd_iface->config_fname); - if (conf == NULL) - goto fail; - hapd_iface->conf = conf; - - hapd_iface->num_bss = conf->num_bss; - hapd_iface->bss = os_calloc(conf->num_bss, - sizeof(struct hostapd_data *)); - if (hapd_iface->bss == NULL) - goto fail; - - for (i = 0; i < conf->num_bss; i++) { - hapd = hapd_iface->bss[i] = - hostapd_alloc_bss_data(hapd_iface, conf, - &conf->bss[i]); - if (hapd == NULL) - goto fail; - hapd->msg_ctx = hapd; - } - - return hapd_iface; - -fail: - if (conf) - hostapd_config_free(conf); - if (hapd_iface) { - os_free(hapd_iface->config_fname); - os_free(hapd_iface->bss); - os_free(hapd_iface); - } - return NULL; -} - - static int hostapd_driver_init(struct hostapd_iface *iface) { struct wpa_init_params params; @@ -243,9 +184,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface) } params.bssid = b; params.ifname = hapd->conf->iface; - params.ssid = hapd->conf->ssid.ssid; - params.ssid_len = hapd->conf->ssid.ssid_len; - params.test_socket = hapd->conf->test_socket; + params.driver_params = hapd->iconf->driver_params; params.use_pae_group_addr = hapd->conf->use_pae_group_addr; params.num_bridge = hapd->iface->num_bss; @@ -271,14 +210,35 @@ static int hostapd_driver_init(struct hostapd_iface *iface) if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { + struct wowlan_triggers *triggs; + iface->drv_flags = capa.flags; + iface->smps_modes = capa.smps_modes; iface->probe_resp_offloads = capa.probe_resp_offloads; + iface->extended_capa = capa.extended_capa; + iface->extended_capa_mask = capa.extended_capa_mask; + iface->extended_capa_len = capa.extended_capa_len; + iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; + + triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); + if (triggs && hapd->driver->set_wowlan) { + if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) + wpa_printf(MSG_ERROR, "set_wowlan failed"); + } + os_free(triggs); } return 0; } +/** + * hostapd_interface_init - Read configuration file and init BSS data + * + * This function is used to parse configuration file for a full interface (one + * or more BSSes sharing the same radio) and allocate memory for the BSS + * interfaces. No actiual driver operations are started. + */ static struct hostapd_iface * hostapd_interface_init(struct hapd_interfaces *interfaces, const char *config_fname, int debug) @@ -287,7 +247,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, int k; wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); - iface = hostapd_init(config_fname); + iface = hostapd_init(interfaces, config_fname); if (!iface) return NULL; iface->interfaces = interfaces; @@ -297,13 +257,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, iface->bss[0]->conf->logger_stdout_level--; } - if (iface->conf->bss[0].iface[0] != 0 || - hostapd_drv_none(iface->bss[0])) { - if (hostapd_driver_init(iface) || - hostapd_setup_interface(iface)) { - hostapd_interface_deinit_free(iface); - return NULL; - } + if (iface->conf->bss[0]->iface[0] == '\0' && + !hostapd_drv_none(iface->bss[0])) { + wpa_printf(MSG_ERROR, "Interface name not specified in %s", + config_fname); + hostapd_interface_deinit_free(iface); + return NULL; } return iface; @@ -346,10 +305,7 @@ static void handle_reload(int sig, void *signal_ctx) static void handle_dump_state(int sig, void *signal_ctx) { -#ifdef HOSTAPD_DUMP_STATE - struct hapd_interfaces *interfaces = signal_ctx; - hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); -#endif /* HOSTAPD_DUMP_STATE */ + /* Not used anymore - ignore signal */ } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -452,7 +408,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, #endif /* EAP_SERVER_TNC */ if (daemonize && os_daemonize(pid_file)) { - perror("daemon"); + wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); return -1; } @@ -468,7 +424,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> " "and contributors\n"); } @@ -480,7 +436,8 @@ static void usage(void) "\n" "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] " "\\\n" - " [-g <global ctrl_iface>] <configuration file(s)>\n" + " [-g <global ctrl_iface>] [-G <group>] \\\n" + " <configuration file(s)>\n" "\n" "options:\n" " -h show this usage\n" @@ -488,11 +445,16 @@ static void usage(void) " -B run daemon in the background\n" " -e entropy file\n" " -g global control interface path\n" + " -G group for control interfaces\n" " -P PID file\n" " -K include key data in debug messages\n" #ifdef CONFIG_DEBUG_FILE " -f log output to debug file instead of stdout\n" #endif /* CONFIG_DEBUG_FILE */ +#ifdef CONFIG_DEBUG_LINUX_TRACING + " -T = record to Linux tracing in addition to logging\n" + " (records all messages regardless of debug verbosity)\n" +#endif /* CONFIG_DEBUG_LINUX_TRACING */ " -t include timestamps in some debug messages\n" " -v show hostapd version\n"); @@ -503,8 +465,9 @@ static void usage(void) static const char * hostapd_msg_ifname_cb(void *ctx) { struct hostapd_data *hapd = ctx; - if (hapd && hapd->iconf && hapd->iconf->bss) - return hapd->iconf->bss->iface; + if (hapd && hapd->iconf && hapd->iconf->bss && + hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) + return hapd->iconf->bss[0]->iface; return NULL; } @@ -519,6 +482,8 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, return -1; pos = os_strrchr(interfaces->global_iface_path, '/'); if (pos == NULL) { + wpa_printf(MSG_ERROR, "No '/' in the global control interface " + "file"); os_free(interfaces->global_iface_path); interfaces->global_iface_path = NULL; return -1; @@ -531,15 +496,57 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, } +static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, + const char *group) +{ +#ifndef CONFIG_NATIVE_WINDOWS + struct group *grp; + grp = getgrnam(group); + if (grp == NULL) { + wpa_printf(MSG_ERROR, "Unknown group '%s'", group); + return -1; + } + interfaces->ctrl_iface_group = grp->gr_gid; +#endif /* CONFIG_NATIVE_WINDOWS */ + return 0; +} + + +#ifdef CONFIG_WPS +static int gen_uuid(const char *txt_addr) +{ + u8 addr[ETH_ALEN]; + u8 uuid[UUID_LEN]; + char buf[100]; + + if (hwaddr_aton(txt_addr, addr) < 0) + return -1; + + uuid_gen_mac_addr(addr, uuid); + if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0) + return -1; + + printf("%s\n", buf); + + return 0; +} +#endif /* CONFIG_WPS */ + + int main(int argc, char *argv[]) { struct hapd_interfaces interfaces; int ret = 1; - size_t i; + size_t i, j; int c, debug = 0, daemonize = 0; char *pid_file = NULL; const char *log_file = NULL; const char *entropy_file = NULL; + char **bss_config = NULL, **tmp_bss; + size_t num_bss_configs = 0; +#ifdef CONFIG_DEBUG_LINUX_TRACING + int enable_trace_dbg = 0; +#endif /* CONFIG_DEBUG_LINUX_TRACING */ if (os_program_init()) return -1; @@ -556,7 +563,7 @@ int main(int argc, char *argv[]) interfaces.global_ctrl_sock = -1; for (;;) { - c = getopt(argc, argv, "Bde:f:hKP:tvg:"); + c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:"); if (c < 0) break; switch (c) { @@ -587,31 +594,65 @@ int main(int argc, char *argv[]) case 't': wpa_debug_timestamp++; break; +#ifdef CONFIG_DEBUG_LINUX_TRACING + case 'T': + enable_trace_dbg = 1; + break; +#endif /* CONFIG_DEBUG_LINUX_TRACING */ case 'v': show_version(); exit(1); break; case 'g': - hostapd_get_global_ctrl_iface(&interfaces, optarg); + if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) + return -1; break; - + case 'G': + if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) + return -1; + break; + case 'b': + tmp_bss = os_realloc_array(bss_config, + num_bss_configs + 1, + sizeof(char *)); + if (tmp_bss == NULL) + goto out; + bss_config = tmp_bss; + bss_config[num_bss_configs++] = optarg; + break; +#ifdef CONFIG_WPS + case 'u': + return gen_uuid(optarg); +#endif /* CONFIG_WPS */ default: usage(); break; } } - if (optind == argc && interfaces.global_iface_path == NULL) + if (optind == argc && interfaces.global_iface_path == NULL && + num_bss_configs == 0) usage(); wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); if (log_file) wpa_debug_open_file(log_file); + else + wpa_debug_setup_stdout(); +#ifdef CONFIG_DEBUG_LINUX_TRACING + if (enable_trace_dbg) { + int tret = wpa_debug_open_linux_tracing(); + if (tret) { + wpa_printf(MSG_ERROR, "Failed to enable trace logging"); + return -1; + } + } +#endif /* CONFIG_DEBUG_LINUX_TRACING */ interfaces.count = argc - optind; - if (interfaces.count) { - interfaces.iface = os_calloc(interfaces.count, + if (interfaces.count || num_bss_configs) { + interfaces.iface = os_calloc(interfaces.count + num_bss_configs, sizeof(struct hostapd_iface *)); if (interfaces.iface == NULL) { wpa_printf(MSG_ERROR, "malloc failed"); @@ -619,30 +660,93 @@ int main(int argc, char *argv[]) } } - if (hostapd_global_init(&interfaces, entropy_file)) + if (hostapd_global_init(&interfaces, entropy_file)) { + wpa_printf(MSG_ERROR, "Failed to initilize global context"); return -1; + } - /* Initialize interfaces */ + /* Allocate and parse configuration for full interface files */ for (i = 0; i < interfaces.count; i++) { interfaces.iface[i] = hostapd_interface_init(&interfaces, argv[optind + i], debug); - if (!interfaces.iface[i]) + if (!interfaces.iface[i]) { + wpa_printf(MSG_ERROR, "Failed to initialize interface"); + goto out; + } + } + + /* Allocate and parse configuration for per-BSS files */ + for (i = 0; i < num_bss_configs; i++) { + struct hostapd_iface *iface; + char *fname; + + wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); + fname = os_strchr(bss_config[i], ':'); + if (fname == NULL) { + wpa_printf(MSG_ERROR, + "Invalid BSS config identifier '%s'", + bss_config[i]); + goto out; + } + *fname++ = '\0'; + iface = hostapd_interface_init_bss(&interfaces, bss_config[i], + fname, debug); + if (iface == NULL) + goto out; + for (j = 0; j < interfaces.count; j++) { + if (interfaces.iface[j] == iface) + break; + } + if (j == interfaces.count) { + struct hostapd_iface **tmp; + tmp = os_realloc_array(interfaces.iface, + interfaces.count + 1, + sizeof(struct hostapd_iface *)); + if (tmp == NULL) { + hostapd_interface_deinit_free(iface); + goto out; + } + interfaces.iface = tmp; + interfaces.iface[interfaces.count++] = iface; + } + } + + /* + * Enable configured interfaces. Depending on channel configuration, + * this may complete full initialization before returning or use a + * callback mechanism to complete setup in case of operations like HT + * co-ex scans, ACS, or DFS are needed to determine channel parameters. + * In such case, the interface will be enabled from eloop context within + * hostapd_global_run(). + */ + interfaces.terminate_on_error = interfaces.count; + for (i = 0; i < interfaces.count; i++) { + if (hostapd_driver_init(interfaces.iface[i]) || + hostapd_setup_interface(interfaces.iface[i])) goto out; } hostapd_global_ctrl_iface_init(&interfaces); - if (hostapd_global_run(&interfaces, daemonize, pid_file)) + if (hostapd_global_run(&interfaces, daemonize, pid_file)) { + wpa_printf(MSG_ERROR, "Failed to start eloop"); goto out; + } ret = 0; out: hostapd_global_ctrl_iface_deinit(&interfaces); /* Deinitialize all interfaces */ - for (i = 0; i < interfaces.count; i++) + for (i = 0; i < interfaces.count; i++) { + if (!interfaces.iface[i]) + continue; + interfaces.iface[i]->driver_ap_teardown = + !!(interfaces.iface[i]->drv_flags & + WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); hostapd_interface_deinit_free(interfaces.iface[i]); + } os_free(interfaces.iface); hostapd_global_deinit(pid_file); @@ -650,6 +754,9 @@ int main(int argc, char *argv[]) if (log_file) wpa_debug_close_file(); + wpa_debug_close_linux_tracing(); + + os_free(bss_config); os_program_deinit(); |