P2P: Add initial version of P2P Module
[libeap.git] / wpa_supplicant / wpa_cli.c
index 272c20e..b97f05d 100644 (file)
@@ -23,6 +23,9 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 #endif /* CONFIG_READLINE */
+#ifdef CONFIG_WPA_CLI_FORK
+#include <sys/wait.h>
+#endif /* CONFIG_WPA_CLI_FORK */
 
 #include "common/wpa_ctrl.h"
 #include "common.h"
@@ -88,6 +91,9 @@ static const char *wpa_cli_full_license =
 
 static struct wpa_ctrl *ctrl_conn;
 static struct wpa_ctrl *mon_conn;
+#ifdef CONFIG_WPA_CLI_FORK
+static pid_t mon_pid = 0;
+#endif /* CONFIG_WPA_CLI_FORK */
 static int wpa_cli_quit = 0;
 static int wpa_cli_attached = 0;
 static int wpa_cli_connected = 0;
@@ -121,6 +127,100 @@ static void usage(void)
 }
 
 
+static void readline_redraw()
+{
+#ifdef CONFIG_READLINE
+       rl_on_new_line();
+       rl_redisplay();
+#endif /* CONFIG_READLINE */
+}
+
+
+static int str_starts(const char *src, const char *match)
+{
+       return os_strncmp(src, match, os_strlen(match)) == 0;
+}
+
+
+static int wpa_cli_show_event(const char *event)
+{
+       const char *start;
+
+       start = os_strchr(event, '>');
+       if (start == NULL)
+               return 1;
+
+       start++;
+       /*
+        * Skip BSS added/removed events since they can be relatively frequent
+        * and are likely of not much use for an interactive user.
+        */
+       if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
+           str_starts(start, WPA_EVENT_BSS_REMOVED))
+               return 0;
+
+       return 1;
+}
+
+
+#ifdef CONFIG_WPA_CLI_FORK
+static int in_query = 0;
+
+static void wpa_cli_monitor_sig(int sig)
+{
+       if (sig == SIGUSR1)
+               in_query = 1;
+       else if (sig == SIGUSR2)
+               in_query = 0;
+}
+
+
+static void wpa_cli_monitor(void)
+{
+       char buf[256];
+       size_t len = sizeof(buf) - 1;
+       struct timeval tv;
+       fd_set rfds;
+       int ppid;
+
+       signal(SIGUSR1, wpa_cli_monitor_sig);
+       signal(SIGUSR2, wpa_cli_monitor_sig);
+
+       ppid = getppid();
+       while (mon_conn) {
+               int s = wpa_ctrl_get_fd(mon_conn);
+               tv.tv_sec = 5;
+               tv.tv_usec = 0;
+               FD_ZERO(&rfds);
+               FD_SET(s, &rfds);
+               if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       perror("select");
+                       break;
+               }
+               if (mon_conn == NULL)
+                       break;
+               if (FD_ISSET(s, &rfds)) {
+                       len = sizeof(buf) - 1;
+                       int res = wpa_ctrl_recv(mon_conn, buf, &len);
+                       if (res < 0) {
+                               perror("wpa_ctrl_recv");
+                               break;
+                       }
+                       buf[len] = '\0';
+                       if (wpa_cli_show_event(buf)) {
+                               if (in_query)
+                                       printf("\r");
+                               printf("%s\n", buf);
+                               kill(ppid, SIGUSR1);
+                       }
+               }
+       }
+}
+#endif /* CONFIG_WPA_CLI_FORK */
+
+
 static int wpa_cli_open_connection(const char *ifname, int attach)
 {
 #if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
@@ -170,6 +270,21 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
                               "wpa_supplicant.\n");
                        return -1;
                }
+
+#ifdef CONFIG_WPA_CLI_FORK
+               {
+                       pid_t p = fork();
+                       if (p < 0) {
+                               perror("fork");
+                               return -1;
+                       }
+                       if (p == 0) {
+                               wpa_cli_monitor();
+                               exit(0);
+                       } else
+                               mon_pid = p;
+               }
+#endif /* CONFIG_WPA_CLI_FORK */
        }
 
        return 0;
@@ -181,6 +296,15 @@ static void wpa_cli_close_connection(void)
        if (ctrl_conn == NULL)
                return;
 
+#ifdef CONFIG_WPA_CLI_FORK
+       if (mon_pid) {
+               int status;
+               kill(mon_pid, SIGPIPE);
+               wait(&status);
+               mon_pid = 0;
+       }
+#endif /* CONFIG_WPA_CLI_FORK */
+
        if (wpa_cli_attached) {
                wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
                wpa_cli_attached = 0;
@@ -247,6 +371,19 @@ static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int ret;
+       if (argc == 0)
+               return -1;
+       ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
+       if (ret < 0 || (size_t) ret >= sizeof(cmd))
+               return -1;
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "MIB");
@@ -519,7 +656,7 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
        if (argc == 2)
                res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
                                  argv[0], argv[1]);
-       else if (argc == 6) {
+       else if (argc == 5 || argc == 6) {
                char ssid_hex[2 * 32 + 1];
                char key_hex[2 * 64 + 1];
                int i;
@@ -532,10 +669,13 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
                }
 
                key_hex[0] = '\0';
-               for (i = 0; i < 64; i++) {
-                       if (argv[5][i] == '\0')
-                               break;
-                       os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
+               if (argc == 6) {
+                       for (i = 0; i < 64; i++) {
+                               if (argv[5][i] == '\0')
+                                       break;
+                               os_snprintf(&key_hex[i * 2], 3, "%02x",
+                                           argv[5][i]);
+                       }
                }
 
                res = os_snprintf(cmd, sizeof(cmd),
@@ -568,8 +708,12 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
 static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
                                    char *argv[])
 {
+       char cmd[100];
+       if (argc > 0) {
+               os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
+               return wpa_ctrl_command(ctrl, cmd);
+       }
        return wpa_ctrl_command(ctrl, "WPS_ER_START");
-
 }
 
 
@@ -587,15 +731,21 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
        char cmd[256];
        int res;
 
-       if (argc != 2) {
-               printf("Invalid WPS_ER_PIN command: need two arguments:\n"
+       if (argc < 2) {
+               printf("Invalid WPS_ER_PIN command: need at least two "
+                      "arguments:\n"
                       "- UUID: use 'any' to select any\n"
-                      "- PIN: Enrollee PIN\n");
+                      "- PIN: Enrollee PIN\n"
+                      "optional: - Enrollee MAC address\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
-                         argv[0], argv[1]);
+       if (argc > 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
+                                 argv[0], argv[1], argv[2]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
+                                 argv[0], argv[1]);
        if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
                printf("Too long WPS_ER_PIN command.\n");
                return -1;
@@ -649,6 +799,57 @@ static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc == 5 || argc == 6) {
+               char ssid_hex[2 * 32 + 1];
+               char key_hex[2 * 64 + 1];
+               int i;
+
+               ssid_hex[0] = '\0';
+               for (i = 0; i < 32; i++) {
+                       if (argv[2][i] == '\0')
+                               break;
+                       os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
+               }
+
+               key_hex[0] = '\0';
+               if (argc == 6) {
+                       for (i = 0; i < 64; i++) {
+                               if (argv[5][i] == '\0')
+                                       break;
+                               os_snprintf(&key_hex[i * 2], 3, "%02x",
+                                           argv[5][i]);
+                       }
+               }
+
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "WPS_ER_CONFIG %s %s %s %s %s %s",
+                                 argv[0], argv[1], ssid_hex, argv[3], argv[4],
+                                 key_hex);
+       } else {
+               printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
+                      "- AP UUID\n"
+                      "- AP PIN\n"
+                      "- new SSID\n"
+                      "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
+                      "- new encr (NONE, WEP, TKIP, CCMP)\n"
+                      "- new key\n");
+               return -1;
+       }
+
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_ER_CONFIG command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        char cmd[256];
@@ -1283,7 +1484,7 @@ static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
                       "address, is required.\n");
                return -1;
        }
-       snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+       os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
        return wpa_ctrl_command(ctrl, buf);
 }
 
@@ -1331,7 +1532,7 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
        if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
                return 0;
        do {
-               snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+               os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
        } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
 
        return -1;
@@ -1339,6 +1540,44 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
 #endif /* CONFIG_AP */
 
 
+static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "SUSPEND");
+}
+
+
+static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "RESUME");
+}
+
+
+static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DROP_SA");
+}
+
+
+static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[128];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid ROAM command: needs one argument "
+                      "(target AP's BSSID)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long ROAM command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 enum wpa_cli_cmd_flags {
        cli_cmd_flag_none               = 0x00,
        cli_cmd_flag_sensitive          = 0x01
@@ -1358,6 +1597,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "ping", wpa_cli_cmd_ping,
          cli_cmd_flag_none,
          "= pings wpa_supplicant" },
+       { "note", wpa_cli_cmd_note,
+         cli_cmd_flag_none,
+         "<text> = add a note to wpa_supplicant debug log" },
        { "mib", wpa_cli_cmd_mib,
          cli_cmd_flag_none,
          "= get MIB variables (dot1x, dot11)" },
@@ -1509,7 +1751,7 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
        { "wps_er_start", wpa_cli_cmd_wps_er_start,
          cli_cmd_flag_none,
-         "= start Wi-Fi Protected Setup External Registrar" },
+         "[IP address] = start Wi-Fi Protected Setup External Registrar" },
        { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
          cli_cmd_flag_none,
          "= stop Wi-Fi Protected Setup External Registrar" },
@@ -1522,6 +1764,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> = learn AP configuration" },
+       { "wps_er_config", wpa_cli_cmd_wps_er_config,
+         cli_cmd_flag_sensitive,
+         "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
        { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
          cli_cmd_flag_none,
          "<addr> = request RSN authentication with <addr> in IBSS" },
@@ -1533,6 +1778,15 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_none,
          "= get information about all associated stations (AP)" },
 #endif /* CONFIG_AP */
+       { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
+         "= notification of suspend/hibernate" },
+       { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+         "= notification of resume/thaw" },
+       { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+         "= drop SA without deauth/disassoc (test command)" },
+       { "roam", wpa_cli_cmd_roam,
+         cli_cmd_flag_none,
+         "<addr> = roam to the specified BSS" },
        { NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -1760,10 +2014,13 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
                        if (action_monitor)
                                wpa_cli_action_process(buf);
                        else {
-                               if (in_read && first)
-                                       printf("\n");
-                               first = 0;
-                               printf("%s\n", buf);
+                               if (wpa_cli_show_event(buf)) {
+                                       if (in_read && first)
+                                               printf("\r");
+                                       first = 0;
+                                       printf("%s\n", buf);
+                                       readline_redraw();
+                               }
                        }
                } else {
                        printf("Could not read pending message.\n");
@@ -1802,14 +2059,59 @@ static char * wpa_cli_cmd_gen(const char *text, int state)
 
 static char * wpa_cli_dummy_gen(const char *text, int state)
 {
+       int i;
+
+       for (i = 0; wpa_cli_commands[i].cmd; i++) {
+               const char *cmd = wpa_cli_commands[i].cmd;
+               size_t len = os_strlen(cmd);
+               if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
+                   rl_line_buffer[len] == ' ') {
+                       printf("\n%s\n", wpa_cli_commands[i].usage);
+                       readline_redraw();
+                       break;
+               }
+       }
+
+       rl_attempted_completion_over = 1;
+       return NULL;
+}
+
+
+static char * wpa_cli_status_gen(const char *text, int state)
+{
+       static int i, len;
+       char *options[] = {
+               "verbose", NULL
+       };
+       char *t;
+
+       if (state == 0) {
+               i = 0;
+               len = os_strlen(text);
+       }
+
+       while ((t = options[i])) {
+               i++;
+               if (os_strncasecmp(t, text, len) == 0)
+                       return strdup(t);
+       }
+
+       rl_attempted_completion_over = 1;
        return NULL;
 }
 
 
 static char ** wpa_cli_completion(const char *text, int start, int end)
 {
-       return rl_completion_matches(text, start == 0 ?
-                                    wpa_cli_cmd_gen : wpa_cli_dummy_gen);
+       char * (*func)(const char *text, int state);
+
+       if (start == 0)
+               func = wpa_cli_cmd_gen;
+       else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
+               func = wpa_cli_status_gen;
+       else
+               func = wpa_cli_dummy_gen;
+       return rl_completion_matches(text, func);
 }
 #endif /* CONFIG_READLINE */
 
@@ -1850,6 +2152,10 @@ static void wpa_cli_interactive(void)
 #ifndef CONFIG_NATIVE_WINDOWS
                alarm(ping_interval);
 #endif /* CONFIG_NATIVE_WINDOWS */
+#ifdef CONFIG_WPA_CLI_FORK
+               if (mon_pid)
+                       kill(mon_pid, SIGUSR1);
+#endif /* CONFIG_WPA_CLI_FORK */
 #ifdef CONFIG_READLINE
                cmd = readline("> ");
                if (cmd && *cmd) {
@@ -1905,6 +2211,10 @@ static void wpa_cli_interactive(void)
 
                if (cmd != cmdbuf)
                        free(cmd);
+#ifdef CONFIG_WPA_CLI_FORK
+               if (mon_pid)
+                       kill(mon_pid, SIGUSR2);
+#endif /* CONFIG_WPA_CLI_FORK */
        } while (!wpa_cli_quit);
 
 #ifdef CONFIG_READLINE
@@ -1994,6 +2304,14 @@ static void wpa_cli_terminate(int sig)
 }
 
 
+#ifdef CONFIG_WPA_CLI_FORK
+static void wpa_cli_usr1(int sig)
+{
+       readline_redraw();
+}
+#endif /* CONFIG_WPA_CLI_FORK */
+
+
 #ifndef CONFIG_NATIVE_WINDOWS
 static void wpa_cli_alarm(int sig)
 {
@@ -2141,6 +2459,9 @@ int main(int argc, char *argv[])
 #ifndef CONFIG_NATIVE_WINDOWS
        signal(SIGALRM, wpa_cli_alarm);
 #endif /* CONFIG_NATIVE_WINDOWS */
+#ifdef CONFIG_WPA_CLI_FORK
+       signal(SIGUSR1, wpa_cli_usr1);
+#endif /* CONFIG_WPA_CLI_FORK */
 
        if (ctrl_ifname == NULL)
                ctrl_ifname = wpa_cli_get_default_ifname();