diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index ce25d03..03e6047 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2197,7 +2197,7 @@ struct wpa_driver_ops {
         * struct wpa_driver_capa.
         */
        int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
-                                u16 config_methods);
+                                u16 config_methods, int join);

        /**
         * p2p_sd_request - Schedule a service discovery query
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index c307505..27acb4b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -113,6 +113,36 @@ static const char * p2p_state_txt(int state)
        }
 }

+int p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+struct p2p_device *dev = NULL;
+
+       if(!addr || !p2p) {
+               return 0;
+       }
+
+       dev = p2p_get_device(p2p, addr);
+       if(dev)
+               return dev->wps_prov_info;
+       else
+               return 0;
+}
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+       struct p2p_device *dev = NULL;
+
+       if(!iface_addr || !p2p) {
+               return;
+       }
+
+       dev = p2p_get_device_interface(p2p, iface_addr);
+       if(dev)
+               dev->wps_prov_info = 0;
+       else
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: "
+               "Device ("MACSTR") not Found", MAC2STR(iface_addr));
+}

 void p2p_set_state(struct p2p_data *p2p, int new_state)
 {
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 1501a20..05a50fe 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1035,6 +1035,24 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr);
  */
 void p2p_group_formation_failed(struct p2p_data *p2p);

+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @mac_addr: Peer Interface address
+ *
+ * This function is used to clear stored WPS provisioning info
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
+/**
+ * p2p_get_provisioning_info - get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @mac_addr: Peer Device address
+ *
+ * This function is used to retreive stored WPS provisioning Info for a given
+ * peer mac_addr.
+ */
+int p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);

 /* Event notifications from lower layer driver operations */

diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 9d72a1c..081ef2d 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -73,6 +73,12 @@ struct p2p_device {
         */
        u16 req_config_methods;

+       /**
+        * wps_prov_info - Store provision info till Group formation is
+        * completed (failure or success).
+        */
+       u16 wps_prov_info;
+
 #define P2P_DEV_PROBE_REQ_ONLY BIT(0)
 #define P2P_DEV_REPORTED BIT(1)
 #define P2P_DEV_NOT_YET_READY BIT(2)
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index f7ff06c..ac086b9 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -267,6 +267,10 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
        }
+
+       /* Store the provisioning info */
+       dev->wps_prov_info = msg.wps_config_methods;
+
        p2p_parse_free(&msg);

 out:
@@ -352,6 +356,9 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
        if (config_methods == 0)
                return -1;

+       /* Reset provisioning info */
+       dev->wps_prov_info = 0;
+
        dev->req_config_methods = config_methods;
        if (join)
                dev->flags |= P2P_DEV_PD_FOR_JOIN;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index b2789be..015a692 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2463,6 +2463,7 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
 {
        u8 addr[ETH_ALEN];
        char *pos;
+       int join = FALSE;

        /* <addr> <config method> */

@@ -2474,7 +2475,10 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        pos++;

-       return wpas_p2p_prov_disc(wpa_s, addr, pos);
+       if (os_strstr(pos, "join") != NULL)
+               join = TRUE;
+
+       return wpas_p2p_prov_disc(wpa_s, addr, pos, join);
 }


diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index f2c5a18..39faeae 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -692,7 +692,7 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
            os_strcmp(config_method, "pushbutton"))
                return wpas_dbus_error_invalid_args(message, NULL);

-       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
+       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, join) < 0)
                return wpas_dbus_error_unknown_error(message,
                                "Failed to send provision discovery request");

diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 8b584db..d61b3fd 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -569,12 +569,12 @@ static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,

 static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
                                            const u8 *peer_addr,
-                                           u16 config_methods)
+                                           u16 config_methods, int join)
 {
        if (!wpa_s->driver->p2p_prov_disc_req)
                return -1;
        return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
-                                               config_methods);
+                                               config_methods, join);
 }

 static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index c6484af..13003a6 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2294,6 +2294,12 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->driver && wpa_s->drv_priv)
                wpa_drv_probe_req_report(wpa_s, 0);
+
+       if(wpa_s->go_params) {
+               /* Clear any stored provisioning info */
+               p2p_clear_provisioning_info(wpa_s->global->p2p, wpa_s->go_params->peer_interface_addr);
+       }
+
        os_free(wpa_s->go_params);
        wpa_s->go_params = NULL;
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2503,6 +2509,15 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                        break;
                }

+               if((p2p_get_provisioning_info(wpa_s->global->p2p,
+                                                       wpa_s->pending_join_dev_addr) == method)) {
+                       /* We already have the provisioning info. Proceed to Join */
+                       wpa_printf(MSG_DEBUG, "P2P: Provisioning for "MACSTR "already done"
+                               "Proceed to Join", MAC2STR(wpa_s->pending_join_dev_addr));
+                       wpa_s->pending_pd_before_join = 0;
+                       goto start;
+               }
+
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr, method, 1)
                    < 0) {
@@ -3256,6 +3271,9 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return;
        }

+       /* Clear any stored provisioning info */
+       p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr);
+
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
                             NULL);
        if (wpa_s->global->p2p)
@@ -3274,35 +3292,42 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
                           "provisioning not in progress");
                return;
        }
+
+       if(wpa_s->go_params) {
+               p2p_clear_provisioning_info(wpa_s->global->p2p, wpa_s->go_params->peer_interface_addr);
+       }
+
        wpas_notify_p2p_wps_failed(wpa_s, fail);
 }


 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                      const char *config_method)
+                      const char *config_method, int join)
 {
        u16 config_methods;

-       if (os_strcmp(config_method, "display") == 0)
+       if (os_strncmp(config_method, "display", 7) == 0)
                config_methods = WPS_CONFIG_DISPLAY;
-       else if (os_strcmp(config_method, "keypad") == 0)
+       else if (os_strncmp(config_method, "keypad", 6) == 0)
                config_methods = WPS_CONFIG_KEYPAD;
-       else if (os_strcmp(config_method, "pbc") == 0 ||
-                os_strcmp(config_method, "pushbutton") == 0)
+       else if (os_strncmp(config_method, "pbc", 3) == 0 ||
+                os_strncmp(config_method, "pushbutton", 10) == 0)
                config_methods = WPS_CONFIG_PUSHBUTTON;
-       else
+       else {
+               wpa_printf(MSG_DEBUG, "P2P: Unkown config method");
                return -1;
+       }

        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
                return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
-                                                config_methods);
+                                                config_methods, join);
        }

        if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
                return -1;

        return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
-                                config_methods, 0);
+                                config_methods, join);
 }


diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 9a13f9f..33b22db 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -43,7 +43,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                          int registrar);
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                      const char *config_method);
+                      const char *config_method, int join);
 void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
                                const u8 *data, size_t data_len,
                                enum p2p_send_action_result result);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 3311a01..9ebb0ab 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2074,15 +2074,19 @@ static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
        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';
