Update to new version 0.8.16 from BRCM
Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date: Tue Dec 27 23:21:45 2011 +0200
P2P: Reject p2p_group_add if forced frequency is not acceptable
Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index f09a6f0..a110171 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 <cutils/properties.h>
@@ -103,6 +104,15 @@
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 DEFINE_DL_LIST(p2p_groups); /* 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 +136,164 @@
}
+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);
+}
+
+
+#ifdef CONFIG_P2P
+static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
+{
+ const char *end;
+ char *buf;
+ end = os_strchr(txt, ' ');
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = os_malloc(end - txt + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, txt, end - txt);
+ buf[end - txt] = '\0';
+ cli_txt_list_del(txt_list, buf);
+ os_free(buf);
+}
+#endif /* CONFIG_P2P */
+
+
+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;
+}
+
+
+#ifdef CONFIG_P2P
+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 int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
+{
+ const char *end;
+ char *buf;
+ int ret;
+ end = os_strchr(txt, ' ');
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = os_malloc(end - txt + 1);
+ if (buf == NULL)
+ return -1;
+ os_memcpy(buf, txt, end - txt);
+ buf[end - txt] = '\0';
+ ret = cli_txt_list_add(txt_list, buf);
+ os_free(buf);
+ return ret;
+}
+#endif /* CONFIG_P2P */
+
+
+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;
@@ -286,8 +454,11 @@
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
- return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
+ if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
+ if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-WPS");
+ return wpa_ctrl_command(ctrl, "STATUS");
}
@@ -381,13 +552,17 @@
return 0;
}
- if (argc != 2) {
+ if (argc != 1 && argc != 2) {
printf("Invalid SET command: needs two arguments (variable "
"name and value)\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+ if (argc == 1)
+ res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
+ argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET command.\n");
return -1;
@@ -1499,6 +1674,21 @@
}
+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[])
{
@@ -1792,6 +1982,21 @@
}
+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[])
{
@@ -1829,6 +2034,21 @@
}
+static char ** wpa_cli_complete_p2p_group_remove(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_groups);
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1857,15 +2077,19 @@
char cmd[128];
int res;
- if (argc != 2) {
- printf("Invalid P2P_PROV_DISC command: needs two arguments "
- "(address and config method\n"
- "(display, keypad, or pbc)\n");
+ if (argc != 2 && argc != 3) {
+ printf("Invalid P2P_PROV_DISC command: needs at least "
+ "two arguments, address and config method\n"
+ "(display, keypad, or pbc) and an optional join\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
- argv[0], argv[1]);
+ if (argc == 3)
+ res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
+ argv[0], argv[1], argv[2]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
+ argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -2099,6 +2323,21 @@
}
+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)
@@ -2144,13 +2383,13 @@
if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
addr, sizeof(addr), discovered))
- return 0;
+ return -1;
do {
os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
} while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
discovered) == 0);
- return -1;
+ return 0;
}
@@ -2267,6 +2506,80 @@
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc == 0)
+ return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
+
+ res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid INTERWORKING_CONNECT commands: needs one "
+ "argument (BSSID)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
+ argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid ANQP_GET command: needs two arguments "
+ "(addr and info id list)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+ return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2357,6 +2670,13 @@
}
+static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
+}
+
+
static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -2472,7 +2792,7 @@
"blacklist = display the blacklist" },
{ "log_level", wpa_cli_cmd_log_level,
cli_cmd_flag_none,
- "<level> [<timestamp>] = update the log level/timestamp of wpa_supplicant\n"
+ "<level> [<timestamp>] = update the log level/timestamp\n"
"log_level = display the current log level and log options" },
{ "list_networks", wpa_cli_cmd_list_networks,
cli_cmd_flag_none,
@@ -2690,6 +3010,21 @@
{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+ { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+ "= fetch ANQP information for all APs" },
+ { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+ "= stop fetch_anqp operation" },
+ { "interworking_select", wpa_cli_cmd_interworking_select,
+ cli_cmd_flag_none,
+ "[auto] = perform Interworking network selection" },
+ { "interworking_connect", wpa_cli_cmd_interworking_connect,
+ cli_cmd_flag_none,
+ "<BSSID> = connect using Interworking credentials" },
+ { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+ "<addr> <info id>[,<info id>]... = request ANQP information" },
+#endif /* CONFIG_INTERWORKING */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
{ "tdls_discover", wpa_cli_cmd_tdls_discover,
@@ -2704,6 +3039,8 @@
{ "signal_poll", wpa_cli_cmd_signal_poll,
cli_cmd_flag_none,
"= get signal parameters" },
+ { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+ "= trigger IEEE 802.1X/EAPOL reauthentication" },
{ "driver", wpa_cli_cmd_driver,
cli_cmd_flag_none,
"<command> = driver private commands" },
@@ -2784,6 +3121,17 @@
{
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);
+ if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
+ return wpa_cli_complete_p2p_group_remove(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();
@@ -2961,19 +3309,20 @@
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPS_EVENT_FAIL)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, AP_STA_CONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
}
-#ifdef ANDROID_BRCM_P2P_PATCH
- else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
- }
-#endif
}
@@ -2992,6 +3341,74 @@
}
+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;
+ }
+
+ if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_add_word(&p2p_groups, s + 1);
+ return;
+ }
+
+ if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_del_word(&p2p_groups, s + 1);
+ return;
+ }
+#endif /* CONFIG_P2P */
+}
+
+
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
{
if (ctrl_conn == NULL) {
@@ -3006,6 +3423,7 @@
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);
@@ -3120,6 +3538,9 @@
eloop_run();
+ cli_txt_list_flush(&p2p_peers);
+ cli_txt_list_flush(&p2p_groups);
+ 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);