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.
This commit is contained in:
parent
6604da3cf0
commit
a624f20bcd
3 changed files with 238 additions and 0 deletions
|
@ -84,6 +84,7 @@ OBJS_p += src/utils/wpa_debug.c
|
||||||
OBJS_p += src/utils/wpabuf.c
|
OBJS_p += src/utils/wpabuf.c
|
||||||
OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
|
OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
|
||||||
OBJS_c += src/utils/wpa_debug.c
|
OBJS_c += src/utils/wpa_debug.c
|
||||||
|
OBJS_c += src/utils/common.c
|
||||||
OBJS_d =
|
OBJS_d =
|
||||||
OBJS_priv =
|
OBJS_priv =
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ OBJS_p += ../src/utils/wpa_debug.o
|
||||||
OBJS_p += ../src/utils/wpabuf.o
|
OBJS_p += ../src/utils/wpabuf.o
|
||||||
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
|
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
|
||||||
OBJS_c += ../src/utils/wpa_debug.o
|
OBJS_c += ../src/utils/wpa_debug.o
|
||||||
|
OBJS_c += ../src/utils/common.o
|
||||||
|
|
||||||
ifndef CONFIG_OS
|
ifndef CONFIG_OS
|
||||||
ifdef CONFIG_NATIVE_WINDOWS
|
ifdef CONFIG_NATIVE_WINDOWS
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
#include "utils/edit.h"
|
#include "utils/edit.h"
|
||||||
|
#include "utils/list.h"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
@ -103,6 +104,14 @@ static const char *action_file = NULL;
|
||||||
static int ping_interval = 5;
|
static int ping_interval = 5;
|
||||||
static int interactive = 0;
|
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 print_help(void);
|
||||||
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
|
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)
|
static int str_starts(const char *src, const char *match)
|
||||||
{
|
{
|
||||||
return os_strncmp(src, match, os_strlen(match)) == 0;
|
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,
|
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
|
||||||
char *argv[])
|
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,
|
static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
|
||||||
char *argv[])
|
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,
|
static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
|
||||||
char *addr, size_t addr_len,
|
char *addr, size_t addr_len,
|
||||||
int discovered)
|
int discovered)
|
||||||
|
@ -2854,6 +3026,15 @@ static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
|
||||||
{
|
{
|
||||||
int i;
|
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++) {
|
for (i = 0; wpa_cli_commands[i].cmd; i++) {
|
||||||
if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
|
if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
|
||||||
edit_clear_line();
|
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)
|
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
|
||||||
{
|
{
|
||||||
if (ctrl_conn == NULL) {
|
if (ctrl_conn == NULL) {
|
||||||
|
@ -3071,6 +3304,7 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
|
||||||
if (action_monitor)
|
if (action_monitor)
|
||||||
wpa_cli_action_process(buf);
|
wpa_cli_action_process(buf);
|
||||||
else {
|
else {
|
||||||
|
cli_event(buf);
|
||||||
if (wpa_cli_show_event(buf)) {
|
if (wpa_cli_show_event(buf)) {
|
||||||
edit_clear_line();
|
edit_clear_line();
|
||||||
printf("\r%s\n", buf);
|
printf("\r%s\n", buf);
|
||||||
|
@ -3185,6 +3419,8 @@ static void wpa_cli_interactive(void)
|
||||||
|
|
||||||
eloop_run();
|
eloop_run();
|
||||||
|
|
||||||
|
cli_txt_list_flush(&p2p_peers);
|
||||||
|
cli_txt_list_flush(&bsses);
|
||||||
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
|
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
|
||||||
os_free(hfile);
|
os_free(hfile);
|
||||||
eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
|
eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
|
||||||
|
|
Loading…
Reference in a new issue