Add support for virtual interface creation/deletion
[mech_eap.git] / wpa_supplicant / wpa_cli.c
index 311cd1f..27f10f1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -28,7 +28,7 @@
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -333,7 +333,7 @@ static int wpa_cli_open_connection(const char *ifname, int attach)
                        return -1;
                res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
                                  ifname);
-               if (res < 0 || res >= flen) {
+               if (os_snprintf_error(flen, res)) {
                        os_free(cfile);
                        return -1;
                }
@@ -448,13 +448,13 @@ static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
        end = buf + buflen;
 
        res = os_snprintf(pos, end - pos, "%s", cmd);
-       if (res < 0 || res >= end - pos)
+       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 (res < 0 || res >= end - pos)
+               if (os_snprintf_error(end - pos, res))
                        goto fail;
                pos += res;
        }
@@ -584,7 +584,7 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
        if (argc == 1) {
                res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
-               if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               if (os_snprintf_error(sizeof(cmd), res)) {
                        printf("Too long SET command.\n");
                        return -1;
                }
@@ -608,35 +608,57 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
                "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps",
                "no_keep_alive",
                /* global configuration parameters */
-               "eapol_version", "ap_scan", "disable_scan_offload",
-               "fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
-               "pkcs11_module_path", "openssl_ciphers",
-               "pcsc_reader", "pcsc_pin",
-               "driver_param", "dot11RSNAConfigPMKLifetime",
+#ifdef CONFIG_CTRL_IFACE
+               "ctrl_interface", "no_ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+               "eapol_version", "ap_scan", "bgscan",
+#ifdef CONFIG_MESH
+               "user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+               "disable_scan_offload", "fast_reauth", "opensc_engine_path",
+               "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+               "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+               "dot11RSNAConfigPMKLifetime",
                "dot11RSNAConfigPMKReauthThreshold",
                "dot11RSNAConfigSATimeout",
-               "update_config", "load_dynamic_eap", "uuid", "device_name",
-               "manufacturer", "model_name", "model_number", "serial_number",
-               "device_type", "os_version", "config_methods",
-               "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type",
+#ifndef CONFIG_NO_CONFIG_WRITE
+               "update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+               "load_dynamic_eap",
+#ifdef CONFIG_WPS
+               "uuid", "device_name", "manufacturer", "model_name",
+               "model_number", "serial_number", "device_type", "os_version",
+               "config_methods", "wps_cred_processing", "wps_vendor_ext_m1",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+               "sec_device_type",
                "p2p_listen_reg_class", "p2p_listen_channel",
-               "p2p_oper_reg_class", "p2p_oper_channel",
-               "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
-               "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
-               "p2p_no_go_freq",
-               "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
-               "p2p_go_vht",
-               "p2p_ignore_shared_freq", "country", "bss_max_count",
-               "bss_expiration_age", "bss_expiration_scan_count",
-               "filter_ssids", "filter_rssi", "max_num_sta",
-               "disassoc_low_ack", "hs20", "interworking", "hessid",
-               "access_network_type", "pbc_in_m1", "autoscan",
-               "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey",
-               "wps_nfc_dev_pw", "ext_password_backend",
+               "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+               "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+               "p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan",
+               "p2p_no_go_freq", "p2p_add_cli_chan",
+               "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+               "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+               "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+               "ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+               "country", "bss_max_count", "bss_expiration_age",
+               "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+               "max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+               "hs20",
+#endif /* CONFIG_HS20 */
+               "interworking", "hessid", "access_network_type", "pbc_in_m1",
+               "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
+               "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
                "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
-               "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
-               "ignore_old_scan_res", "freq_list", "external_sim",
-               "tdls_external_control", "p2p_search_delay"
+               "sae_groups", "dtim_period", "beacon_int",
+               "ap_vendor_elements", "ignore_old_scan_res", "freq_list",
+               "scan_cur_freq", "sched_scan_interval",
+               "tdls_external_control", "osu_dir", "wowlan_triggers",
+               "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+               "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+               "reassoc_same_bss_optim"
        };
        int i, num_fields = ARRAY_SIZE(fields);
 
@@ -658,6 +680,11 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
        return NULL;
 }
 
+static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "DUMP");
+}
+
 
 static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -665,6 +692,74 @@ static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static char ** wpa_cli_complete_get(const char *str, int pos)
+{
+       int arg = get_cmd_arg_num(str, pos);
+       const char *fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+               "ctrl_interface", "ctrl_interface_group",
+#endif /* CONFIG_CTRL_IFACE */
+               "eapol_version", "ap_scan",
+#ifdef CONFIG_MESH
+               "user_mpm", "max_peer_links", "mesh_max_inactivity",
+#endif /* CONFIG_MESH */
+               "disable_scan_offload", "fast_reauth", "opensc_engine_path",
+               "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers",
+               "pcsc_reader", "pcsc_pin", "external_sim", "driver_param",
+               "dot11RSNAConfigPMKLifetime",
+               "dot11RSNAConfigPMKReauthThreshold",
+               "dot11RSNAConfigSATimeout",
+#ifndef CONFIG_NO_CONFIG_WRITE
+               "update_config",
+#endif /* CONFIG_NO_CONFIG_WRITE */
+#ifdef CONFIG_WPS
+               "device_name", "manufacturer", "model_name", "model_number",
+               "serial_number", "config_methods", "wps_cred_processing",
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+               "p2p_listen_reg_class", "p2p_listen_channel",
+               "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent",
+               "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss",
+               "p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan",
+               "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
+               "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
+               "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
+               "ip_addr_start", "ip_addr_end",
+#endif /* CONFIG_P2P */
+               "bss_max_count", "bss_expiration_age",
+               "bss_expiration_scan_count", "filter_ssids", "filter_rssi",
+               "max_num_sta", "disassoc_low_ack",
+#ifdef CONFIG_HS20
+               "hs20",
+#endif /* CONFIG_HS20 */
+               "interworking", "access_network_type", "pbc_in_m1", "autoscan",
+               "wps_nfc_dev_pw_id", "ext_password_backend",
+               "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+               "dtim_period", "beacon_int", "ignore_old_scan_res",
+               "scan_cur_freq", "sched_scan_interval",
+               "tdls_external_control", "osu_dir", "wowlan_triggers",
+               "p2p_search_delay", "mac_addr", "rand_addr_lifetime",
+               "preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
+               "reassoc_same_bss_optim"
+       };
+       int i, num_fields = ARRAY_SIZE(fields);
+
+       if (arg == 1) {
+               char **res = os_calloc(num_fields + 1, sizeof(char *));
+               if (res == NULL)
+                       return NULL;
+               for (i = 0; i < num_fields; i++) {
+                       res[i] = os_strdup(fields[i]);
+                       if (res[i] == NULL)
+                               return res;
+               }
+               return res;
+       }
+
+       return NULL;
+}
+
+
 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_ctrl_command(ctrl, "LOGOFF");
@@ -733,7 +828,7 @@ static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
                res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
        else
                res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long BSS_FLUSH command.\n");
                return -1;
        }
@@ -908,7 +1003,7 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
                return -1;
        }
 
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long WPS_REG command.\n");
                return -1;
        }
@@ -1033,7 +1128,7 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+       if (os_snprintf_error(sizeof(cmd), res)) {
                printf("Too long WPS_ER_CONFIG command.\n");
                return -1;
        }
@@ -1085,14 +1180,14 @@ static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long IDENTITY command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long IDENTITY command.\n");
                        return -1;
                }
@@ -1118,14 +1213,14 @@ static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long PASSWORD command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long PASSWORD command.\n");
                        return -1;
                }
@@ -1152,14 +1247,14 @@ static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long NEW_PASSWORD command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long NEW_PASSWORD command.\n");
                        return -1;
                }
@@ -1185,14 +1280,14 @@ static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long PIN command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long PIN command.\n");
                        return -1;
                }
@@ -1217,14 +1312,14 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long OTP command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long OTP command.\n");
                        return -1;
                }
@@ -1250,14 +1345,14 @@ static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long SIM command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long SIM command.\n");
                        return -1;
                }
@@ -1283,14 +1378,14 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
        pos = cmd;
        ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
                          argv[0], argv[1]);
-       if (ret < 0 || ret >= end - pos) {
+       if (os_snprintf_error(end - pos, ret)) {
                printf("Too long PASSPHRASE command.\n");
                return -1;
        }
        pos += ret;
        for (i = 2; i < argc; i++) {
                ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        printf("Too long PASSPHRASE command.\n");
                        return -1;
                }
@@ -1577,6 +1672,10 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
        wpa_cli_close_connection();
        os_free(ctrl_ifname);
        ctrl_ifname = os_strdup(argv[0]);
+       if (!ctrl_ifname) {
+               printf("Failed to allocate memory\n");
+               return 0;
+       }
 
        if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
                printf("Connected to interface '%s.\n", ctrl_ifname);
@@ -1612,21 +1711,21 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
                printf("Invalid INTERFACE_ADD command: needs at least one "
                       "argument (interface name)\n"
                       "All arguments: ifname confname driver ctrl_interface "
-                      "driver_param bridge_name\n");
+                      "driver_param bridge_name [create]\n");
                return -1;
        }
 
        /*
         * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
-        * <driver_param>TAB<bridge_name>
+        * <driver_param>TAB<bridge_name>[TAB<create>]
         */
        res = os_snprintf(cmd, sizeof(cmd),
-                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+                         "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s",
                          argv[0],
                          argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
                          argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
-                         argc > 5 ? argv[5] : "");
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+                         argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "");
+       if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
@@ -1754,6 +1853,13 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
 #ifdef CONFIG_MESH
 
+static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
+}
+
+
 static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
@@ -1814,6 +1920,20 @@ static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
+                                             char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
+}
+
+
 static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -1898,11 +2018,9 @@ static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
 {
        char cmd[4096];
 
-       if (argc != 2 && argc != 4) {
+       if (argc < 2) {
                printf("Invalid P2P_SERV_DISC_REQ command: needs two "
-                      "arguments (address and TLVs) or four arguments "
-                      "(address, \"upnp\", version, search target "
-                      "(SSDP ST:)\n");
+                      "or more arguments (address and TLVs)\n");
                return -1;
        }
 
@@ -1933,7 +2051,7 @@ static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
                          argv[0], argv[1], argv[2], argv[3]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
@@ -1964,27 +2082,25 @@ static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
 static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
                                       char *argv[])
 {
-       char cmd[4096];
-       int res;
+       if (argc < 3) {
+               printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
+               return -1;
+       }
+
+       return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
+}
+
 
-       if (argc != 3 && argc != 4) {
-               printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
+                                      char *argv[])
+{
+       if (argc < 5 || argc > 6) {
+               printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
                       "arguments\n");
                return -1;
        }
 
-       if (argc == 4)
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_SERVICE_ADD %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd),
-                                 "P2P_SERVICE_ADD %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
-               return -1;
-       cmd[sizeof(cmd) - 1] = '\0';
-       return wpa_ctrl_command(ctrl, cmd);
+       return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
 }
 
 
@@ -2008,7 +2124,7 @@ static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
                res = os_snprintf(cmd, sizeof(cmd),
                                  "P2P_SERVICE_DEL %s %s",
                                  argv[0], argv[1]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
@@ -2230,7 +2346,7 @@ static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
                          argv[0], argc > 1 ? argv[1] : "");
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
@@ -2251,7 +2367,7 @@ static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
 
        res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
                          argv[0]);
-       if (res < 0 || (size_t) res >= sizeof(cmd))
+       if (os_snprintf_error(sizeof(cmd), res))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
        return wpa_ctrl_command(ctrl, cmd);
@@ -2288,6 +2404,13 @@ static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc,
+                                               char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
@@ -2412,6 +2535,27 @@ static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "WMM_AC_STATUS");
+}
+
+
+static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
+                                              char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -2496,6 +2640,26 @@ static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
+static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
+}
+
+
 enum wpa_cli_cmd_flags {
        cli_cmd_flag_none               = 0x00,
        cli_cmd_flag_sensitive          = 0x01
@@ -2547,7 +2711,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_none,
          "= set variables (shows list of variables when run without "
          "arguments)" },
-       { "get", wpa_cli_cmd_get, NULL,
+       { "dump", wpa_cli_cmd_dump, NULL,
+         cli_cmd_flag_none,
+         "= dump config variables" },
+       { "get", wpa_cli_cmd_get, wpa_cli_complete_get,
          cli_cmd_flag_none,
          "<name> = get information" },
        { "logon", wpa_cli_cmd_logon, NULL,
@@ -2814,6 +2981,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_none,
          "<addr> = roam to the specified BSS" },
 #ifdef CONFIG_MESH
+       { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
+         cli_cmd_flag_none,
+         "[ifname] = Create a new mesh interface" },
        { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
          cli_cmd_flag_none,
          "<network id> = join a mesh network (disable others)" },
@@ -2827,6 +2997,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
        { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
          "= stop P2P Devices search" },
+       { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
+         cli_cmd_flag_none,
+         "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
+       { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
+         cli_cmd_flag_none,
+         "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
        { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
          cli_cmd_flag_none,
          "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
@@ -2863,8 +3039,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "= remove all stored service entries" },
        { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
          cli_cmd_flag_none,
-         "<bonjour|upnp> <query|version> <response|service> = add a local "
+         "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
          "service" },
+       { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
+         cli_cmd_flag_none,
+         "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
+         "local ASP service" },
        { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
          cli_cmd_flag_none,
          "<bonjour|upnp> <query|version> [|service] = remove a local "
@@ -2922,6 +3102,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "interworking_connect", wpa_cli_cmd_interworking_connect,
          wpa_cli_complete_bss, cli_cmd_flag_none,
          "<BSSID> = connect using Interworking credentials" },
+       { "interworking_add_network", wpa_cli_cmd_interworking_add_network,
+         wpa_cli_complete_bss, cli_cmd_flag_none,
+         "<BSSID> = connect using Interworking credentials" },
        { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
          cli_cmd_flag_none,
          "<addr> <info id>[,<info id>]... = request ANQP information" },
@@ -2969,6 +3152,17 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL,
          cli_cmd_flag_none,
          "<tsid> = delete WMM-AC traffic stream" },
+       { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
+         cli_cmd_flag_none,
+         "= show status for Wireless Multi-Media Admission-Control" },
+       { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
+         cli_cmd_flag_none,
+         "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
+         "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
+         "with TDLS peer" },
+       { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
+         cli_cmd_flag_none,
+         "<addr> = disable channel switching with TDLS peer <addr>" },
        { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
          cli_cmd_flag_none,
          "= get signal parameters" },
@@ -3001,6 +3195,18 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
          "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
        },
+       { "neighbor_rep_request",
+         wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
+         "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
+         "(with optional given SSID, default: current SSID)"
+       },
+       { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
+         "= flush ERP keys" },
+       { "mac_rand_scan",
+         wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
+         "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
+         "mask=mac-address-mask] = scan MAC randomization"
+       },
        { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -3575,7 +3781,11 @@ static void start_edit(void)
        ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
+#ifdef CONFIG_WPA_CLI_HISTORY_DIR
+       home = CONFIG_WPA_CLI_HISTORY_DIR;
+#else /* CONFIG_WPA_CLI_HISTORY_DIR */
        home = getenv("HOME");
+#endif /* CONFIG_WPA_CLI_HISTORY_DIR */
        if (home) {
                const char *fname = ".wpa_cli_history";
                int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
@@ -3651,7 +3861,7 @@ static void update_ifnames(struct wpa_ctrl *ctrl)
                        break;
                *end = '\0';
                ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
-               if (ret > 0 && ret < (int) sizeof(txt))
+               if (!os_snprintf_error(sizeof(txt), ret))
                        cli_txt_list_add(&ifnames, txt);
                pos = end + 1;
        }
@@ -3669,7 +3879,8 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
        if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
                if (!warning_displayed) {
                        printf("Could not connect to wpa_supplicant: "
-                              "%s - re-trying\n", ctrl_ifname);
+                              "%s - re-trying\n",
+                              ctrl_ifname ? ctrl_ifname : "(nil)");
                        warning_displayed = 1;
                }
                eloop_register_timeout(1, 0, try_connection, NULL, NULL);
@@ -3930,7 +4141,8 @@ int main(int argc, char *argv[])
                    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
                        fprintf(stderr, "Failed to connect to non-global "
                                "ctrl_ifname: %s  error: %s\n",
-                               ctrl_ifname, strerror(errno));
+                               ctrl_ifname ? ctrl_ifname : "(nil)",
+                               strerror(errno));
                        return -1;
                }