]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wpa_cli: Add completion functions for P2P peers and BSSes
authorJouni Malinen <j@w1.fi>
Fri, 28 Oct 2011 20:37:34 +0000 (23:37 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 28 Oct 2011 20:50:37 +0000 (23:50 +0300)
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
wpa_supplicant/Makefile
wpa_supplicant/wpa_cli.c

index 9392b6d002af90cbb94254af0948510fe74522db..b45ab4680749bc8ad6289abcfccfb609ce46c3f1 100644 (file)
@@ -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 =
 
index 93dea3c089c437f32662f4ac47cbba61a685e700..0eec94c37b79946bf4416f5b9bd31204eda07812 100644 (file)
@@ -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
index 02670fefb610a9846c9a589f64c7550265326c9f..a31115325c03a0a4fa8593fee8d93314971890f2 100644 (file)
@@ -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 <cutils/properties.h>
@@ -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);