From a624f20bcd8f30ae4088af7a7e42f77d466f2697 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 28 Oct 2011 23:37:34 +0300 Subject: [PATCH] wpa_cli: Add completion functions for P2P peers and BSSes Keep a local list of found P2P peers and BSS entries and use those to complete arguments for p2p_peer, p2p_connect, and bss commands. --- wpa_supplicant/Android.mk | 1 + wpa_supplicant/Makefile | 1 + wpa_supplicant/wpa_cli.c | 236 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 9392b6d00..b45ab4680 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -84,6 +84,7 @@ OBJS_p += src/utils/wpa_debug.c OBJS_p += src/utils/wpabuf.c OBJS_c = wpa_cli.c src/common/wpa_ctrl.c OBJS_c += src/utils/wpa_debug.c +OBJS_c += src/utils/common.c OBJS_d = OBJS_priv = diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 93dea3c08..0eec94c37 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -66,6 +66,7 @@ OBJS_p += ../src/utils/wpa_debug.o OBJS_p += ../src/utils/wpabuf.o OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o OBJS_c += ../src/utils/wpa_debug.o +OBJS_c += ../src/utils/common.o ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 02670fefb..a31115325 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -24,6 +24,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/edit.h" +#include "utils/list.h" #include "common/version.h" #ifdef ANDROID #include @@ -103,6 +104,14 @@ static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; +struct cli_txt_entry { + struct dl_list list; + char *txt; +}; + +static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ + static void print_help(void); static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); @@ -126,6 +135,124 @@ static void usage(void) } +static void cli_txt_list_free(struct cli_txt_entry *e) +{ + dl_list_del(&e->list); + os_free(e->txt); + os_free(e); +} + + +static void cli_txt_list_flush(struct dl_list *list) +{ + struct cli_txt_entry *e; + while ((e = dl_list_first(list, struct cli_txt_entry, list))) + cli_txt_list_free(e); +} + + +static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list, + const char *txt) +{ + struct cli_txt_entry *e; + dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { + if (os_strcmp(e->txt, txt) == 0) + return e; + } + return NULL; +} + + +static void cli_txt_list_del(struct dl_list *txt_list, const char *txt) +{ + struct cli_txt_entry *e; + e = cli_txt_list_get(txt_list, txt); + if (e) + cli_txt_list_free(e); +} + + +static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt) +{ + u8 addr[ETH_ALEN]; + char buf[18]; + if (hwaddr_aton(txt, addr) < 0) + return; + os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + cli_txt_list_del(txt_list, buf); +} + + +static int cli_txt_list_add(struct dl_list *txt_list, const char *txt) +{ + struct cli_txt_entry *e; + e = cli_txt_list_get(txt_list, txt); + if (e) + return 0; + e = os_zalloc(sizeof(*e)); + if (e == NULL) + return -1; + e->txt = os_strdup(txt); + if (e->txt == NULL) { + os_free(e); + return -1; + } + dl_list_add(txt_list, &e->list); + return 0; +} + + +static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt) +{ + u8 addr[ETH_ALEN]; + char buf[18]; + if (hwaddr_aton(txt, addr) < 0) + return -1; + os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + return cli_txt_list_add(txt_list, buf); +} + + +static char ** cli_txt_list_array(struct dl_list *txt_list) +{ + unsigned int i, count = dl_list_len(txt_list); + char **res; + struct cli_txt_entry *e; + + res = os_zalloc((count + 1) * sizeof(char *)); + if (res == NULL) + return NULL; + + i = 0; + dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { + res[i] = os_strdup(e->txt); + if (res[i] == NULL) + break; + i++; + } + + return res; +} + + +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; @@ -1503,6 +1630,21 @@ static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static char ** wpa_cli_complete_bss(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&bsses); + break; + } + + return res; +} + + static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1796,6 +1938,21 @@ static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, } +static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&p2p_peers); + break; + } + + return res; +} + + static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2103,6 +2260,21 @@ static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&p2p_peers); + break; + } + + return res; +} + + static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd, char *addr, size_t addr_len, int discovered) @@ -2854,6 +3026,15 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str, { int i; + if (os_strcasecmp(cmd, "bss") == 0) + return wpa_cli_complete_bss(str, pos); +#ifdef CONFIG_P2P + if (os_strcasecmp(cmd, "p2p_connect") == 0) + return wpa_cli_complete_p2p_connect(str, pos); + if (os_strcasecmp(cmd, "p2p_peer") == 0) + return wpa_cli_complete_p2p_peer(str, pos); +#endif /* CONFIG_P2P */ + for (i = 0; wpa_cli_commands[i].cmd; i++) { if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) { edit_clear_line(); @@ -3057,6 +3238,58 @@ static void wpa_cli_reconnect(void) } +static void cli_event(const char *str) +{ + const char *start, *s; + + start = os_strchr(str, '>'); + if (start == NULL) + return; + + start++; + + if (str_starts(start, WPA_EVENT_BSS_ADDED)) { + s = os_strchr(start, ' '); + if (s == NULL) + return; + s = os_strchr(s + 1, ' '); + if (s == NULL) + return; + cli_txt_list_add(&bsses, s + 1); + return; + } + + if (str_starts(start, WPA_EVENT_BSS_REMOVED)) { + s = os_strchr(start, ' '); + if (s == NULL) + return; + s = os_strchr(s + 1, ' '); + if (s == NULL) + return; + cli_txt_list_del_addr(&bsses, s + 1); + return; + } + +#ifdef CONFIG_P2P + if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) { + s = os_strstr(start, " p2p_dev_addr="); + if (s == NULL) + return; + cli_txt_list_add_addr(&p2p_peers, s + 14); + return; + } + + if (str_starts(start, P2P_EVENT_DEVICE_LOST)) { + s = os_strstr(start, " p2p_dev_addr="); + if (s == NULL) + return; + cli_txt_list_del_addr(&p2p_peers, s + 14); + return; + } +#endif /* CONFIG_P2P */ +} + + static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) { if (ctrl_conn == NULL) { @@ -3071,6 +3304,7 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) if (action_monitor) wpa_cli_action_process(buf); else { + cli_event(buf); if (wpa_cli_show_event(buf)) { edit_clear_line(); printf("\r%s\n", buf); @@ -3185,6 +3419,8 @@ static void wpa_cli_interactive(void) eloop_run(); + cli_txt_list_flush(&p2p_peers); + cli_txt_list_flush(&bsses); edit_deinit(hfile, wpa_cli_edit_filter_history_cb); os_free(hfile); eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);