@@ -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
@@ -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)
{
@@ -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 */
@@ -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)
@@ -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;
@@ -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);
}
@@ -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");
@@ -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,
@@ -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);
}
@@ -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);
@@ -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';