}
+u16 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;
+}
+
+
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
*/
void p2p_group_formation_failed(struct p2p_data *p2p);
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Interface Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
/* Event notifications from lower layer driver operations */
*/
u16 req_config_methods;
+ /**
+ * wps_prov_info - Stored provisioning WPS config method
+ *
+ * This is used to store pending WPS config method between Provisioning
+ * Discovery and connection to a running group.
+ */
+ 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)
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:
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;
{
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);
break;
}
+ if ((p2p_get_provisioning_info(wpa_s->global->p2p,
+ wpa_s->pending_join_dev_addr) ==
+ method)) {
+ /*
+ * We have already performed provision discovery for
+ * joining the group. Proceed directly to join
+ * operation without duplicated provision discovery. */
+ wpa_printf(MSG_DEBUG, "P2P: Provisioning discovery "
+ "with " 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) {
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)
"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);
}