Make driver flags available through control interface
[mech_eap.git] / hostapd / hostapd_cli.c
index 6121762..5c1f297 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include <dirent.h>
 
 #include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/edit.h"
 #include "common/version.h"
 
+#ifndef CONFIG_NO_CTRL_IFACE
 
-static const char *hostapd_cli_version =
+static const char *const hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
 
 
-static const char *hostapd_cli_license =
+static const char *const hostapd_cli_license =
 "This software may be distributed under the terms of the BSD license.\n"
 "See README for more details.\n";
 
-static const char *hostapd_cli_full_license =
+static const char *const hostapd_cli_full_license =
 "This software may be distributed under the terms of the BSD license.\n"
 "\n"
 "Redistribution and use in source and binary forms, with or without\n"
@@ -56,7 +58,7 @@ static const char *hostapd_cli_full_license =
 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
 "\n";
 
-static const char *commands_help =
+static const char *const commands_help =
 "Commands:\n"
 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
 "   sta <addr>           get MIB variables for one station\n"
@@ -96,6 +98,7 @@ static int hostapd_cli_attached = 0;
 #define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
 #endif /* CONFIG_CTRL_IFACE_DIR */
 static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+static const char *client_socket_dir = NULL;
 
 static char *ctrl_ifname = NULL;
 static const char *pid_file = NULL;
@@ -111,13 +114,15 @@ static void usage(void)
                "\n"
                "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
                "[-a<path>] \\\n"
-               "                   [-G<ping interval>] [command..]\n"
+               "                   [-P<pid file>] [-G<ping interval>] [command..]\n"
                "\n"
                "Options:\n"
                "   -h           help (show this usage text)\n"
                "   -v           shown version information\n"
                "   -p<path>     path to find control sockets (default: "
                "/var/run/hostapd)\n"
+               "   -s<dir_path> dir path to open client sockets (default: "
+               CONFIG_CTRL_IFACE_DIR ")\n"
                "   -a<file>     run in daemon mode executing the action file "
                "based on events\n"
                "                from hostapd\n"
@@ -132,21 +137,35 @@ static void usage(void)
 
 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *cfile;
        int flen;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
 
        if (ifname == NULL)
                return NULL;
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+       ctrl_conn = wpa_ctrl_open(ifname);
+       return ctrl_conn;
+#else /* CONFIG_CTRL_IFACE_UDP */
        flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
        cfile = malloc(flen);
        if (cfile == NULL)
                return NULL;
        snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
 
-       ctrl_conn = wpa_ctrl_open(cfile);
+       if (client_socket_dir && client_socket_dir[0] &&
+           access(client_socket_dir, F_OK) < 0) {
+               perror(client_socket_dir);
+               free(cfile);
+               return NULL;
+       }
+
+       ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
        free(cfile);
        return ctrl_conn;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
@@ -204,6 +223,52 @@ static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
 }
 
 
+static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+                    char *argv[])
+{
+       int i, res;
+       char *pos, *end;
+
+       pos = buf;
+       end = buf + buflen;
+
+       res = os_snprintf(pos, end - pos, "%s", cmd);
+       if (os_snprintf_error(end - pos, res))
+               goto fail;
+       pos += res;
+
+       for (i = 0; i < argc; i++) {
+               res = os_snprintf(pos, end - pos, " %s", argv[i]);
+               if (os_snprintf_error(end - pos, res))
+                       goto fail;
+               pos += res;
+       }
+
+       buf[buflen - 1] = '\0';
+       return 0;
+
+fail:
+       printf("Too long command\n");
+       return -1;
+}
+
+
+static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
+                          int min_args, int argc, char *argv[])
+{
+       char buf[4096];
+
+       if (argc < min_args) {
+               printf("Invalid %s command - at least %d argument%s required.\n",
+                      cmd, min_args, min_args > 1 ? "s are" : " is");
+               return -1;
+       }
+       if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "PING");
@@ -393,7 +458,7 @@ static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
        else
                res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
                                  argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long WPS_CHECK_PIN command.\n");
                return -1;
        }
@@ -456,7 +521,7 @@ static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
 
        res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
                          argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
                return -1;
        }
@@ -477,7 +542,7 @@ static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
        }
 
        res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long WPS_NFC_TOKEN command.\n");
                return -1;
        }
@@ -499,7 +564,7 @@ static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
 
        res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
                          argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long NFC_GET_HANDOVER_SEL command.\n");
                return -1;
        }
@@ -541,7 +606,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
        char buf[256];
-       char ssid_hex[2 * 32 + 1];
+       char ssid_hex[2 * SSID_MAX_LEN + 1];
        char key_hex[2 * 64 + 1];
        int i;
 
@@ -552,7 +617,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
        }
 
        ssid_hex[0] = '\0';
-       for (i = 0; i < 32; i++) {
+       for (i = 0; i < SSID_MAX_LEN; i++) {
                if (argv[0][i] == '\0')
                        break;
                os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
@@ -596,7 +661,7 @@ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
                          argv[0], argv[1]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -616,7 +681,7 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
                          argv[0], argv[1], argv[2]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -634,14 +699,14 @@ static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
        }
 
        res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
 
        total = res;
        for (i = 1; i < argc; i++) {
                tmp = &buf[total];
                res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
-               if (res < 0 || (size_t) res >= sizeof(buf) - total - 1)
+               if (os_snprintf_error(sizeof(buf) - total, res))
                        return -1;
                total += res;
        }
@@ -736,7 +801,7 @@ static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
        }
 
        res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -755,7 +820,7 @@ static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
        }
 
        res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -775,7 +840,7 @@ static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
                          argv[0], argv[1]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -800,7 +865,7 @@ static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc,
                res = os_snprintf(buf, sizeof(buf),
                                  "HS20_DEAUTH_REQ %s %s %s",
                                  argv[0], argv[1], argv[2]);
-       if (res < 0 || res >= (int) sizeof(buf))
+       if (os_snprintf_error(sizeof(buf), res))
                return -1;
        return wpa_ctrl_command(ctrl, buf);
 }
@@ -893,7 +958,7 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
        }
 
        res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long SET command.\n");
                return -1;
        }
@@ -913,7 +978,7 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
        }
 
        res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long GET command.\n");
                return -1;
        }
@@ -921,6 +986,35 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+#ifdef CONFIG_FST
+static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+       int i;
+       int total;
+
+       if (argc <= 0) {
+               printf("FST command: parameters are required.\n");
+               return -1;
+       }
+
+       total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
+
+       for (i = 0; i < argc; i++) {
+               res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
+                                 argv[i]);
+               if (os_snprintf_error(sizeof(cmd) - total, res)) {
+                       printf("Too long fst command.\n");
+                       return -1;
+               }
+               total += res;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_FST */
+
+
 static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
                                       int argc, char *argv[])
 {
@@ -941,7 +1035,7 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
 
        res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
                          argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long CHAN_SWITCH command.\n");
                return -1;
        }
@@ -950,7 +1044,7 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
        for (i = 2; i < argc; i++) {
                tmp = cmd + total;
                res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
-               if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+               if (os_snprintf_error(sizeof(cmd) - total, res)) {
                        printf("Too long CHAN_SWITCH command.\n");
                        return -1;
                }
@@ -994,7 +1088,7 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
        res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
                          argc == 3 ? argv[2] : "");
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long VENDOR command.\n");
                return -1;
        }
@@ -1002,12 +1096,141 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
+static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
+                         argc >= 1 ? " " : "",
+                         argc >= 1 ? argv[0] : "",
+                         argc == 2 ? " " : "",
+                         argc == 2 ? argv[1] : "");
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long option\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       if (argc == 0)
+               return -1;
+       return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char cmd[2048];
+       int res;
+
+       if (argc < 3 || argc > 5) {
+               printf("Invalid set_neighbor command: needs 3-5 arguments\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
+                         argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+                         argc == 5 ? argv[4] : "");
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long SET_NEIGHBOR command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       char cmd[400];
+       int res;
+
+       if (argc != 2) {
+               printf("Invalid remove_neighbor command: needs 2 arguments\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
+                         argv[0], argv[1]);
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long REMOVE_NEIGHBOR command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid req_lci command - requires destination address\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
+       if (os_snprintf_error(sizeof(cmd), res)) {
+               printf("Too long REQ_LCI command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       if (argc < 4) {
+               printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
+               return -1;
+       }
+
+       return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
 struct hostapd_cli_cmd {
        const char *cmd;
        int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
 };
 
-static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "ping", hostapd_cli_cmd_ping },
        { "mib", hostapd_cli_cmd_mib },
        { "relog", hostapd_cli_cmd_relog },
@@ -1041,6 +1264,10 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "get_config", hostapd_cli_cmd_get_config },
        { "help", hostapd_cli_cmd_help },
        { "interface", hostapd_cli_cmd_interface },
+#ifdef CONFIG_FST
+       { "fst", hostapd_cli_cmd_fst },
+#endif /* CONFIG_FST */
+       { "raw", hostapd_cli_cmd_raw },
        { "level", hostapd_cli_cmd_level },
        { "license", hostapd_cli_cmd_license },
        { "quit", hostapd_cli_cmd_quit },
@@ -1055,13 +1282,22 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "enable", hostapd_cli_cmd_enable },
        { "reload", hostapd_cli_cmd_reload },
        { "disable", hostapd_cli_cmd_disable },
+       { "erp_flush", hostapd_cli_cmd_erp_flush },
+       { "log_level", hostapd_cli_cmd_log_level },
+       { "pmksa", hostapd_cli_cmd_pmksa },
+       { "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
+       { "set_neighbor", hostapd_cli_cmd_set_neighbor },
+       { "remove_neighbor", hostapd_cli_cmd_remove_neighbor },
+       { "req_lci", hostapd_cli_cmd_req_lci },
+       { "req_range", hostapd_cli_cmd_req_range },
+       { "driver_flags", hostapd_cli_cmd_driver_flags },
        { NULL, NULL }
 };
 
 
 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-       struct hostapd_cli_cmd *cmd, *match = NULL;
+       const struct hostapd_cli_cmd *cmd, *match = NULL;
        int count;
 
        count = 0;
@@ -1276,7 +1512,7 @@ int main(int argc, char *argv[])
                return -1;
 
        for (;;) {
-               c = getopt(argc, argv, "a:BhG:i:p:v");
+               c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
                if (c < 0)
                        break;
                switch (c) {
@@ -1302,6 +1538,12 @@ int main(int argc, char *argv[])
                case 'p':
                        ctrl_iface_dir = optarg;
                        break;
+               case 'P':
+                       pid_file = optarg;
+                       break;
+               case 's':
+                       client_socket_dir = optarg;
+                       break;
                default:
                        usage();
                        return -1;
@@ -1367,7 +1609,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (daemonize && os_daemonize(pid_file))
+       if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
                return -1;
 
        if (interactive)
@@ -1382,3 +1624,12 @@ int main(int argc, char *argv[])
        hostapd_cli_cleanup();
        return 0;
 }
+
+#else /* CONFIG_NO_CTRL_IFACE */
+
+int main(int argc, char *argv[])
+{
+       return -1;
+}
+
+#endif /* CONFIG_NO_CTRL_IFACE */