X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=hostapd%2Fhostapd_cli.c;h=c0e27dec3522ee4c4a300cbded750db2afdff25c;hb=977c0796f9b990aa8998477f67a9bc6a6d424e2d;hp=ff133f6aeef2d331a1f14bdcc804d2a22e4e649a;hpb=220754c5535e89ede0664fa55e6f6cc4e92f0a59;p=mech_eap.git diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index ff133f6..c0e27de 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -15,6 +15,7 @@ #include "utils/eloop.h" #include "utils/edit.h" #include "common/version.h" +#include "common/cli.h" #ifndef CONFIG_NO_CTRL_IFACE @@ -58,38 +59,6 @@ static const char *const hostapd_cli_full_license = "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" "\n"; -static const char *const commands_help = -"Commands:\n" -" mib get MIB variables (dot1x, dot11, radius)\n" -" sta get MIB variables for one station\n" -" all_sta get MIB variables for all stations\n" -" new_sta add a new station\n" -" deauthenticate deauthenticate a station\n" -" disassociate disassociate a station\n" -#ifdef CONFIG_IEEE80211W -" sa_query send SA Query to a station\n" -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS -" wps_pin [timeout] [addr] add WPS Enrollee PIN\n" -" wps_check_pin verify PIN checksum\n" -" wps_pbc indicate button pushed to initiate PBC\n" -" wps_cancel cancel the pending WPS operation\n" -#ifdef CONFIG_WPS_NFC -" wps_nfc_tag_read report read NFC tag with WPS data\n" -" wps_nfc_config_token build NFC configuration token\n" -" wps_nfc_token manager NFC password token\n" -#endif /* CONFIG_WPS_NFC */ -" wps_ap_pin [params..] enable/disable AP PIN\n" -" wps_config configure AP\n" -" wps_get_status show current WPS status\n" -#endif /* CONFIG_WPS */ -" get_config show current configuration\n" -" help show this usage help\n" -" interface [ifname] show interfaces/select interface\n" -" level change debug level\n" -" license show full hostapd_cli license\n" -" quit exit hostapd_cli\n"; - static struct wpa_ctrl *ctrl_conn; static int hostapd_cli_quit = 0; static int hostapd_cli_attached = 0; @@ -106,6 +75,9 @@ static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; +static void print_help(FILE *stream, const char *cmd); +static char ** list_cmd_list(void); + static void usage(void) { @@ -129,9 +101,32 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n" - "%s", - commands_help); + " socket path)\n\n"); + print_help(stderr, NULL); +} + + +static int get_cmd_arg_num(const char *str, int pos) +{ + int arg = 0, i; + + for (i = 0; i <= pos; i++) { + if (str[i] != ' ') { + arg++; + while (i <= pos && str[i] != ' ') + i++; + } + } + + if (arg > 0) + arg--; + return arg; +} + + +static int str_starts(const char *src, const char *match) +{ + return os_strncmp(src, match, os_strlen(match)) == 0; } @@ -774,11 +769,26 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - printf("%s", commands_help); + print_help(stdout, argc > 0 ? argv[0] : NULL); return 0; } +static char ** hostapd_cli_complete_help(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = list_cmd_list(); + break; + } + + return res; +} + + static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1218,75 +1228,143 @@ static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); +} + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); + char ** (*completion)(const char *str, int pos); + const char *usage; }; static const struct hostapd_cli_cmd hostapd_cli_commands[] = { - { "ping", hostapd_cli_cmd_ping }, - { "mib", hostapd_cli_cmd_mib }, - { "relog", hostapd_cli_cmd_relog }, - { "status", hostapd_cli_cmd_status }, - { "sta", hostapd_cli_cmd_sta }, - { "all_sta", hostapd_cli_cmd_all_sta }, - { "new_sta", hostapd_cli_cmd_new_sta }, - { "deauthenticate", hostapd_cli_cmd_deauthenticate }, - { "disassociate", hostapd_cli_cmd_disassociate }, + { "ping", hostapd_cli_cmd_ping, NULL, + "= pings hostapd" }, + { "mib", hostapd_cli_cmd_mib, NULL, + "= get MIB variables (dot1x, dot11, radius)" }, + { "relog", hostapd_cli_cmd_relog, NULL, NULL }, + { "status", hostapd_cli_cmd_status, NULL, NULL }, + { "sta", hostapd_cli_cmd_sta, NULL, + " = get MIB variables for one station" }, + { "all_sta", hostapd_cli_cmd_all_sta, NULL, + "= get MIB variables for all stations" }, + { "new_sta", hostapd_cli_cmd_new_sta, NULL, + " = add a new station" }, + { "deauthenticate", hostapd_cli_cmd_deauthenticate, NULL, + " = deauthenticate a station" }, + { "disassociate", hostapd_cli_cmd_disassociate, NULL, + " = disassociate a station" }, #ifdef CONFIG_IEEE80211W - { "sa_query", hostapd_cli_cmd_sa_query }, + { "sa_query", hostapd_cli_cmd_sa_query, NULL, + " = send SA Query to a station" }, #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS - { "wps_pin", hostapd_cli_cmd_wps_pin }, - { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, - { "wps_pbc", hostapd_cli_cmd_wps_pbc }, - { "wps_cancel", hostapd_cli_cmd_wps_cancel }, + { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, + " [timeout] [addr] = add WPS Enrollee PIN" }, + { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, + " = verify PIN checksum" }, + { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, + "= indicate button pushed to initiate PBC" }, + { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, + "= cancel the pending WPS operation" }, #ifdef CONFIG_WPS_NFC - { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read }, - { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token }, - { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token }, - { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel }, + { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, + " = report read NFC tag with WPS data" }, + { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, + " = build NFC configuration token" }, + { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, + " = manager NFC password token" }, + { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, + NULL }, #endif /* CONFIG_WPS_NFC */ - { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, - { "wps_config", hostapd_cli_cmd_wps_config }, - { "wps_get_status", hostapd_cli_cmd_wps_get_status }, + { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, + " [params..] = enable/disable AP PIN" }, + { "wps_config", hostapd_cli_cmd_wps_config, NULL, + " = configure AP" }, + { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, + "= show current WPS status" }, #endif /* CONFIG_WPS */ - { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent }, - { "ess_disassoc", hostapd_cli_cmd_ess_disassoc }, - { "bss_tm_req", hostapd_cli_cmd_bss_tm_req }, - { "get_config", hostapd_cli_cmd_get_config }, - { "help", hostapd_cli_cmd_help }, - { "interface", hostapd_cli_cmd_interface }, + { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL }, + { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL }, + { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL }, + { "get_config", hostapd_cli_cmd_get_config, NULL, + "= show current configuration" }, + { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, + "= show this usage help" }, + { "interface", hostapd_cli_cmd_interface, NULL, + "[ifname] = show interfaces/select interface" }, #ifdef CONFIG_FST - { "fst", hostapd_cli_cmd_fst }, + { "fst", hostapd_cli_cmd_fst, NULL, NULL }, #endif /* CONFIG_FST */ - { "raw", hostapd_cli_cmd_raw }, - { "level", hostapd_cli_cmd_level }, - { "license", hostapd_cli_cmd_license }, - { "quit", hostapd_cli_cmd_quit }, - { "set", hostapd_cli_cmd_set }, - { "get", hostapd_cli_cmd_get }, - { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set }, - { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf }, - { "chan_switch", hostapd_cli_cmd_chan_switch }, - { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif }, - { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req }, - { "vendor", hostapd_cli_cmd_vendor }, - { "enable", hostapd_cli_cmd_enable }, - { "reload", hostapd_cli_cmd_reload }, - { "disable", hostapd_cli_cmd_disable }, - { "erp_flush", hostapd_cli_cmd_erp_flush }, - { "log_level", hostapd_cli_cmd_log_level }, - { "pmksa", hostapd_cli_cmd_pmksa }, - { "pmksa_flush", hostapd_cli_cmd_pmksa_flush }, - { "set_neighbor", hostapd_cli_cmd_set_neighbor }, - { "remove_neighbor", hostapd_cli_cmd_remove_neighbor }, - { "req_lci", hostapd_cli_cmd_req_lci }, - { "req_range", hostapd_cli_cmd_req_range }, - { NULL, NULL } + { "raw", hostapd_cli_cmd_raw, NULL, NULL }, + { "level", hostapd_cli_cmd_level, NULL, + " = change debug level" }, + { "license", hostapd_cli_cmd_license, NULL, + "= show full hostapd_cli license" }, + { "quit", hostapd_cli_cmd_quit, NULL, + "= exit hostapd_cli" }, + { "set", hostapd_cli_cmd_set, NULL, NULL }, + { "get", hostapd_cli_cmd_get, NULL, NULL }, + { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL }, + { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL }, + { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL }, + { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL }, + { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL }, + { "vendor", hostapd_cli_cmd_vendor, NULL, NULL }, + { "enable", hostapd_cli_cmd_enable, NULL, NULL }, + { "reload", hostapd_cli_cmd_reload, NULL, NULL }, + { "disable", hostapd_cli_cmd_disable, NULL, NULL }, + { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL }, + { "log_level", hostapd_cli_cmd_log_level, NULL, NULL }, + { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL }, + { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL }, + { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL }, + { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL }, + { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL }, + { "req_range", hostapd_cli_cmd_req_range, NULL, NULL }, + { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL }, + { NULL, NULL, NULL, NULL } }; +/* + * Prints command usage, lines are padded with the specified string. + */ +static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, + const char *pad) +{ + char c; + size_t n; + + if (cmd->usage == NULL) + return; + fprintf(stream, "%s%s ", pad, cmd->cmd); + for (n = 0; (c = cmd->usage[n]); n++) { + fprintf(stream, "%c", c); + if (c == '\n') + fprintf(stream, "%s", pad); + } + fprintf(stream, "\n"); +} + + +static void print_help(FILE *stream, const char *cmd) +{ + int n; + + fprintf(stream, "commands:\n"); + for (n = 0; hostapd_cli_commands[n].cmd; n++) { + if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) + print_cmd_help(stream, &hostapd_cli_commands[n], " "); + } +} + + static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { const struct hostapd_cli_cmd *cmd, *match = NULL; @@ -1431,13 +1509,77 @@ static void hostapd_cli_edit_eof_cb(void *ctx) } +static char ** list_cmd_list(void) +{ + char **res; + int i, count; + + count = ARRAY_SIZE(hostapd_cli_commands); + res = os_calloc(count + 1, sizeof(char *)); + if (res == NULL) + return NULL; + + for (i = 0; hostapd_cli_commands[i].cmd; i++) { + res[i] = os_strdup(hostapd_cli_commands[i].cmd); + if (res[i] == NULL) + break; + } + + return res; +} + + +static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, + int pos) +{ + int i; + + for (i = 0; hostapd_cli_commands[i].cmd; i++) { + if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) + continue; + if (hostapd_cli_commands[i].completion) + return hostapd_cli_commands[i].completion(str, pos); + if (!hostapd_cli_commands[i].usage) + return NULL; + edit_clear_line(); + printf("\r%s\n", hostapd_cli_commands[i].usage); + edit_redraw(); + break; + } + + return NULL; +} + + +static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, + int pos) +{ + char **res; + const char *end; + char *cmd; + + end = os_strchr(str, ' '); + if (end == NULL || str + pos < end) + return list_cmd_list(); + + cmd = os_malloc(pos + 1); + if (cmd == NULL) + return NULL; + os_memcpy(cmd, str, pos); + cmd[end - str] = '\0'; + res = hostapd_cli_cmd_completion(cmd, str, pos); + os_free(cmd); + return res; +} + + static void hostapd_cli_interactive(void) { printf("\nInteractive mode\n\n"); eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, - NULL, NULL, NULL, NULL); + hostapd_cli_edit_completion_cb, NULL, NULL, NULL); eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); eloop_run();