/* * FST CLI based main * * Copyright (c) 2015,2019, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include "utils/common.h" #include "utils/os.h" #include "utils/eloop.h" #include "common/defs.h" #define FST_MGR_COMPONENT "MAINCLI" #include "fst_manager.h" #include "fst_ctrl.h" #include "fst_cfgmgr.h" #ifdef ANDROID #include "fst_capconfigstore.h" #include "fst_hidl.h" #endif #define DEFAULT_FST_INIT_RETRY_PERIOD_SEC 1 #define MAX_CTRL_IFACE_SIZE 256 extern Boolean fst_ctrl_create(const char *ctrl_iface, unsigned int ping_interval); extern void fst_ctrl_free(void); /* globals */ unsigned int fst_debug_level = MSG_INFO; unsigned int fst_num_of_retries = 20; unsigned int fst_ping_interval = 1; Boolean fst_force_nc = FALSE; static Boolean fst_main_do_loop = FALSE; static Boolean fst_continuous_loop = FALSE; static Boolean terminate_signalled = FALSE; static Boolean init_done = FALSE; static void fst_manager_signal_terminate(int sig) { fst_mgr_printf(MSG_INFO, "termination signal arrived (%d)", sig); terminate_signalled = TRUE; } static void fst_manager_eloop_terminate(int sig, void *signal_ctx) { eloop_terminate(); fst_manager_signal_terminate(sig); } void fst_manager_terminate(void) { fst_main_do_loop = FALSE; eloop_terminate(); } static void usage(const char *prog) { printf("Usage: %s [options] []\n", prog); printf(", where options are:\n" "\t--version, -V - show version.\n" "\t--daemon, -B - run in daemon mode. Exit after " "wpa_supplicant/hostapd quits\n" "\t--daemonex, -b - continuous daemon mode. Wait for a next " "wpa_supplicant/hostapd\n" "\t--config, -c - read the FST configuration from the file\n" "\t--retries -r - number of session setup retries.\n" "\t--ping-int -p - CLI ping interval in sec, 0 to disable\n" "\t--force-nc -n - force non-compliant mode.\n" "\t--debug, -d - increase debugging verbosity (-dd - more, " "-ddd - even more)\n" "\t--logfile, -f - log output to specified file\n" #ifdef ANDROID "\t--autogen, -a - auto-generate fstman.ini for android " " (mode: 0=supplicant 1=softap)\n" #endif "\t--usage, -u - this message\n" "\t--help, -h - this message\n"); exit(2); } void try_to_init(void *eloop_ctx, void *ctx) { const char *ctrl_iface = (const char *)ctx; if (!fst_ctrl_create(ctrl_iface, fst_ping_interval)) { fst_mgr_printf(MSG_ERROR, "cannot create fst_ctrl"); goto again; } if (fst_manager_init()) { fst_mgr_printf(MSG_ERROR, "cannot init fst manager"); goto error_init; } init_done = TRUE; return; error_init: fst_ctrl_free(); again: eloop_register_timeout(DEFAULT_FST_INIT_RETRY_PERIOD_SEC, 0, try_to_init, NULL, (void*)ctrl_iface); } void main_loop(const char *ctrl_iface) { if (eloop_register_signal_terminate(fst_manager_eloop_terminate, NULL)) { fst_mgr_printf(MSG_ERROR, "eloop_register_signal_terminate"); return; } eloop_run(); fst_mgr_printf(MSG_INFO, "eloop finished"); if (!fst_continuous_loop) fst_main_do_loop = FALSE; if (init_done) { fst_manager_deinit(); fst_ctrl_free(); init_done = FALSE; } } #ifdef ANDROID static const char FSTMAN_IFNAME[] = "wlan0"; static const char FSTMAN_WIGIG_IFNAME[] = "wigig0"; static const char FSTMAN_DATA_IFNAME[] = "bond0"; static const char FSTMAN_SAP_IFNAME[] = "wlan0"; static const char FSTMAN_WIGIG_IF_CHANNEL[] = "2"; static const char FST_STA_INTERFACE_KEY_NAME[] = "fst.wifi.sta.interface"; static const char FST_SAP_INTERFACE_KEY_NAME[] = "fst.wifi.sap.interface"; static const char FST_DATA_INTERFACE_KEY_NAME[] = "fst.data.interface"; static const char FST_WIGIG_INTERFACE_KEY_NAME[] = "fst.wigig.interface"; static const char FST_WIGIG_INTERFACE_CHANNEL_KEY_NAME[] = "fst.wigig.interface.channel"; static int create_fstman_ini_file(int softap_mode, char *buf, int len) { char fst_iface1[64] = { '\0' }; char fst_iface2[64] = { '\0' }; char fst_data_iface[64] = { '\0' }; char fst_wigig_channel[64] = { '\0' }; int result; if (softap_mode) fst_get_config_string(FST_SAP_INTERFACE_KEY_NAME, FSTMAN_SAP_IFNAME, fst_iface1, sizeof(fst_iface1)); else fst_get_config_string(FST_STA_INTERFACE_KEY_NAME, FSTMAN_IFNAME, fst_iface1, sizeof(fst_iface1)); fst_get_config_string(FST_WIGIG_INTERFACE_KEY_NAME, FSTMAN_WIGIG_IFNAME, fst_iface2, sizeof(fst_iface2)); fst_get_config_string(FST_DATA_INTERFACE_KEY_NAME, FSTMAN_DATA_IFNAME, fst_data_iface, sizeof(fst_data_iface)); fst_get_config_string(FST_WIGIG_INTERFACE_CHANNEL_KEY_NAME, FSTMAN_WIGIG_IF_CHANNEL, fst_wigig_channel, sizeof(fst_wigig_channel)); result = snprintf(buf, len, "[fst_manager]\n" "ctrl_iface=/data/vendor/wifi/hostapd/global\n" "groups=%s\n" /* bond0 */ "\n" "[%s]\n" /* bond0 */ "interfaces=%s,%s\n" /* wlan0,wigig0 */ "mux_type=bonding\n" "mux_ifname=%s\n" /* bond0 */ "mux_managed=1\n" "mac_address_by=%s\n" /* wlan0 */ "rate_upgrade_master=%s\n" /* wlan0 */ "txqueuelen=100\n" "rate_upgrade_acl_file=/data/vendor/wifi/fst_rate_upgrade.accept\n" "\n" "[%s]\n" /* wlan0 */ "manual_enslave=1\n" "priority=100\n" "default_llt=3600\n" "\n" "[%s]\n" /* wigig0 */ "manual_enslave=1\n" "priority=110\n" "wpa_group=GCMP\n" "wpa_pairwise=GCMP\n" "hw_mode=ad\n" "channel=%s\n", fst_data_iface, fst_data_iface, fst_iface1, fst_iface2, fst_data_iface, fst_iface1, fst_iface1, fst_iface1, fst_iface2, fst_wigig_channel ); return result; } static bool write_fstman_ini_file(const char *fname, const char *contents, int len) { FILE *f; int written; f = fopen(fname, "w"); if (!f) { fst_mgr_printf(MSG_ERROR, "fail to open %s for writing\n", fname); return false; } written = fwrite(contents, 1, len, f); fclose(f); if (written != len) { fst_mgr_printf(MSG_ERROR, "fail to write to %s\n", fname); return false; } return true; } static int fst_manager_gen_fstman_ini(const char *fname, int softap_mode) { char cfg[2048]; int len; len = create_fstman_ini_file(softap_mode, cfg, sizeof(cfg)); if (len <= 0) return -1; if (!write_fstman_ini_file(fname, cfg, len)) return -1; return 0; } #endif /* ANDROID */ int main(int argc, char *argv[]) { const struct option long_opts[] = { {"version", no_argument, NULL, 'V'}, {"daemon", no_argument, NULL, 'B'}, {"daemonex", no_argument, NULL, 'b'}, {"config", required_argument, NULL, 'c'}, {"retries", required_argument, NULL, 'r'}, {"ping-int", required_argument, NULL, 'p'}, {"force-nc", no_argument, NULL, 'n'}, {"debug", optional_argument, NULL, 'd'}, {"logfile", required_argument, NULL, 'f'}, {"autogen", required_argument, NULL, 'a'}, {"usage", no_argument, NULL, 'u'}, {"help", no_argument, NULL, 'h'}, {} }; int res = -1; char short_opts[] = "VBbc:r:nd::f:a:uh"; const char *ctrl_iface = NULL; char *fstman_config_file = NULL; int opt, i, mode; char buf[MAX_CTRL_IFACE_SIZE]; #ifdef ANDROID void *priv; #endif while ((opt = getopt_long_only(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (opt) { case 'V': printf("FST Manager, version " FST_MANAGER_VERSION "\n"); exit(0); break; case 'B': fst_main_do_loop = TRUE; break; case 'b': fst_main_do_loop = TRUE; fst_continuous_loop = TRUE; break; case 'c': if (fstman_config_file != NULL) { fst_mgr_printf(MSG_ERROR, "Multiple configurations not allowed\n"); goto error_cfmgr_params; } if (optarg != NULL) fstman_config_file=os_strdup(optarg); if (fstman_config_file == NULL) { fst_mgr_printf(MSG_ERROR, "Filename memory allocation error\n"); goto error_cfmgr_params; } break; case 'r': if (optarg != NULL) fst_num_of_retries = strtoul(optarg, NULL, 0); break; case 'p': if (optarg != NULL) fst_ping_interval = strtoul(optarg, NULL, 0); break; case 'n': fst_force_nc = TRUE; fst_mgr_printf(MSG_INFO, "Non-compliant FST mode forced\n"); break; case 'd': fst_debug_level = MSG_DEBUG; if (optarg && optarg[0] == 'd') { fst_debug_level = MSG_MSGDUMP; if (optarg[1] == 'd') fst_debug_level = MSG_EXCESSIVE; } break; case 'f': if (wpa_debug_open_file(optarg)) { fst_mgr_printf(MSG_ERROR, "Cannot open log file: %s", optarg); goto error_cfmgr_params; } break; #ifdef ANDROID case 'a': if (fstman_config_file == NULL) { fst_mgr_printf(MSG_ERROR, "Config file must be specified\n"); goto error_cfmgr_params; } mode = optarg ? strtoul(optarg, NULL, 0) : 0; res = fst_manager_gen_fstman_ini( fstman_config_file, mode); if (res < 0) { fst_mgr_printf(MSG_ERROR, "fstman.ini gen failure, err: %d\n", res); goto error_cfmgr_params; } break; #endif case 'u': case 'h': case '?': default: usage(argv[0]); break; } } if (!fstman_config_file && argc - optind != 1) { fst_mgr_printf(MSG_ERROR, "either ctrl_interace_name or config has to be specified"); usage(argv[0]); goto error_cfmgr_params; } if (fstman_config_file) i = fst_cfgmgr_init(FST_CONFIG_INI, (void*)fstman_config_file); else i = fst_cfgmgr_init(FST_CONFIG_CLI, NULL); if (i != 0) { fst_mgr_printf(MSG_ERROR, "FST Configuration error"); goto error_cfmgr_init; } if (argc - optind == 1) ctrl_iface = argv[optind]; else if (!fst_cfgmgr_get_ctrl_iface(buf, sizeof(buf))) ctrl_iface = buf; else { fst_mgr_printf(MSG_ERROR, "cannot get ctrl_iface"); goto error_ctrl_iface; } if (eloop_init() != 0) { fst_mgr_printf(MSG_ERROR, "cannot init eloop"); goto error_eloop_init; } #ifdef ANDROID priv = fst_hidl_init(); if (!priv) { fst_mgr_printf(MSG_ERROR, "cannot init HIDL"); goto error_hidl_init; } #endif signal(SIGINT, fst_manager_signal_terminate); signal(SIGTERM, fst_manager_signal_terminate); while (TRUE) { eloop_cancel_timeout(try_to_init, NULL, NULL); eloop_register_timeout(0, 0, try_to_init, NULL, (void*)ctrl_iface); main_loop(ctrl_iface); if (!fst_main_do_loop || terminate_signalled) break; signal(SIGINT, fst_manager_signal_terminate); signal(SIGTERM, fst_manager_signal_terminate); os_sleep(DEFAULT_FST_INIT_RETRY_PERIOD_SEC, 0); } res = 0; #ifdef ANDROID fst_hidl_deinit(priv); #endif error_hidl_init: eloop_destroy(); error_eloop_init: error_ctrl_iface: fst_cfgmgr_deinit(); error_cfmgr_init: error_cfmgr_params: wpa_debug_close_file(); os_free(fstman_config_file); return res; }