P2P: Increase the maximum number of PD Request retries
[mech_eap.git] / src / p2p / p2p_pd.c
index ca248ae..e40f2b7 100644 (file)
 
 
 /*
- * Number of retries to attempt for provision discovery requests during IDLE
- * state in case the peer is not listening.
+ * Number of retries to attempt for provision discovery requests
+ * in case the peer is not listening.
  */
-#define MAX_PROV_DISC_REQ_RETRIES 10
+#define MAX_PROV_DISC_REQ_RETRIES 120
 
 
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
@@ -46,15 +46,22 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
 {
        struct wpabuf *buf;
        u8 *len;
+       size_t extra = 0;
 
-       buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_prov_disc_req)
+               extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       buf = wpabuf_alloc(1000 + extra);
        if (buf == NULL)
                return NULL;
 
        p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
 
        len = p2p_buf_add_ie_hdr(buf);
-       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        p2p_buf_add_device_info(buf, p2p, NULL);
        if (go) {
                p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
@@ -65,17 +72,46 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
        /* WPS IE with Config Methods attribute */
        p2p_build_wps_ie_config_methods(buf, config_methods);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (p2p->wfd_ie_prov_disc_req)
+               wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
 
 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
                                                u8 dialog_token,
-                                               u16 config_methods)
+                                               u16 config_methods,
+                                               const u8 *group_id,
+                                               size_t group_id_len)
 {
        struct wpabuf *buf;
+       size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+       struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
+       if (wfd_ie && group_id) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       struct p2p_group *g = p2p->groups[i];
+                       struct wpabuf *ie;
+                       if (!p2p_group_is_group_id_match(g, group_id,
+                                                        group_id_len))
+                               continue;
+                       ie = p2p_group_get_wfd_ie(g);
+                       if (ie) {
+                               wfd_ie = ie;
+                               break;
+                       }
+               }
+       }
+       if (wfd_ie)
+               extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
 
-       buf = wpabuf_alloc(100);
+       buf = wpabuf_alloc(100 + extra);
        if (buf == NULL)
                return NULL;
 
@@ -84,6 +120,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
        /* WPS IE with Config Methods attribute */
        p2p_build_wps_ie_config_methods(buf, config_methods);
 
+#ifdef CONFIG_WIFI_DISPLAY
+       if (wfd_ie)
+               wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
        return buf;
 }
 
@@ -110,11 +151,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Provision Discovery Request from "
                        "unknown peer " MACSTR, MAC2STR(sa));
-               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
+               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
+               {
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: Provision Discovery Request add device "
                                "failed " MACSTR, MAC2STR(sa));
                }
+       } else if (msg.wfd_subelems) {
+               wpabuf_free(dev->info.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
        }
 
        if (!(msg.wps_config_methods &
@@ -125,6 +170,21 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                goto out;
        }
 
+       if (msg.group_id) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       if (p2p_group_is_group_id_match(p2p->groups[i],
+                                                       msg.group_id,
+                                                       msg.group_id_len))
+                               break;
+               }
+               if (i == p2p->num_groups) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
+                               "request for unknown P2P Group ID - reject");
+                       goto out;
+               }
+       }
+
        if (dev)
                dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
                                P2P_DEV_PD_PEER_KEYPAD);
@@ -145,7 +205,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 
 out:
        resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
-                                       reject ? 0 : msg.wps_config_methods);
+                                       reject ? 0 : msg.wps_config_methods,
+                                       msg.group_id, msg.group_id_len);
        if (resp == NULL) {
                p2p_parse_free(&msg);
                return;
@@ -198,6 +259,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        struct p2p_message msg;
        struct p2p_device *dev;
        u16 report_config_methods = 0;
+       int success = 0;
 
        if (p2p_parse(data, len, &msg))
                return;
@@ -216,11 +278,6 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                return;
        }
 
-       if (p2p->pending_action_state == P2P_PENDING_PD) {
-               os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
-               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
-       }
-
        if (dev->dialog_token != msg.dialog_token) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Ignore Provision Discovery Response with "
@@ -230,6 +287,11 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                return;
        }
 
+       if (p2p->pending_action_state == P2P_PENDING_PD) {
+               os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+               p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+       }
+
        /*
         * If the response is from the peer to whom a user initiated request
         * was sent earlier, we reset that state info here.
@@ -266,11 +328,21 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        dev->wps_prov_info = msg.wps_config_methods;
 
        p2p_parse_free(&msg);
+       success = 1;
 
 out:
        dev->req_config_methods = 0;
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-       if (p2p->cfg->prov_disc_resp)
+       if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Start GO Neg after the PD-before-GO-Neg "
+                       "workaround with " MACSTR,
+                       MAC2STR(dev->info.p2p_device_addr));
+               dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+               p2p_connect_send(p2p, dev);
+               return;
+       }
+       if (success && p2p->cfg->prov_disc_resp)
                p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
                                         report_config_methods);
 }
@@ -336,7 +408,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-                     u16 config_methods, int join, int force_freq)
+                     u16 config_methods, int join, int force_freq,
+                     int user_initiated_pd)
 {
        struct p2p_device *dev;
 
@@ -374,14 +447,9 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
                return 0;
        }
 
-       /*
-        * We use the join param as a cue to differentiate between user
-        * initiated PD request and one issued during finds (internal).
-        */
-       p2p->user_initiated_pd = !join;
+       p2p->user_initiated_pd = user_initiated_pd;
 
-       /* Also set some retries to attempt in case of IDLE state */
-       if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+       if (p2p->user_initiated_pd)
                p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
 
        return p2p_send_prov_disc_req(p2p, dev, join, force_freq);