]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P2: Refactor provision discovery request/response processing
authorShivani Baranwal <quic_shivbara@quicinc.com>
Mon, 5 Aug 2024 09:33:06 +0000 (15:03 +0530)
committerJouni Malinen <j@w1.fi>
Tue, 27 Aug 2024 07:51:56 +0000 (10:51 +0300)
Parse the P2P IEs in functions that handle provision discovery request
and response. Process the frames based on the IEs received in the PD
frames. This makes it easier to extend PD for P2P2 cases.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
src/p2p/p2p.c
src/p2p/p2p_i.h
src/p2p/p2p_pd.c

index 676a45ce083a22f0df70291553369eee568cfb92..c9a4626328d2084e7f50e92ae00116309719830f 100644 (file)
@@ -1924,10 +1924,10 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
                p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
                break;
        case P2P_PROV_DISC_REQ:
-               p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
+               p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
                break;
        case P2P_PROV_DISC_RESP:
-               p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1);
+               p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1);
                break;
        case P2P_DEV_DISC_REQ:
                p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
index c22630d51fa7f7d8cee43fc0be6ae51133236765..344bece21105399c7d689ab1d9a2947579c43794 100644 (file)
@@ -873,10 +873,10 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
                         struct p2p_device *dev, struct p2p_message *msg);
 
 /* p2p_pd.c */
-void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
-                              const u8 *data, size_t len, int rx_freq);
-void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
-                               const u8 *data, size_t len);
+void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq);
+void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                              const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
                           int join, int force_freq);
 void p2p_reset_pending_pd(struct p2p_data *p2p);
index 6c9ac194acd0e2d5a2c1412a8adac6b734d77c83..c34f69f7f63e49407be965d17a9dde9f16e07581 100644 (file)
@@ -614,10 +614,10 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
 }
 
 
-void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
-                              const u8 *data, size_t len, int rx_freq)
+static void p2p_process_prov_disc_req(struct p2p_data *p2p,
+                                     struct p2p_message *msg, const u8 *sa,
+                                     const u8 *data, size_t len, int rx_freq)
 {
-       struct p2p_message msg;
        struct p2p_device *dev;
        int freq;
        enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
@@ -638,21 +638,17 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        u8 remote_conncap;
        u16 method;
 
-       if (p2p_parse(data, len, &msg))
-               return;
-
        p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
                " with config methods 0x%x (freq=%d)",
-               MAC2STR(sa), msg.wps_config_methods, rx_freq);
-       group_mac = msg.intended_addr;
+               MAC2STR(sa), msg->wps_config_methods, rx_freq);
+       group_mac = msg->intended_addr;
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
                p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
                        MACSTR, MAC2STR(sa));
 
-               if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
-                                  0)) {
+               if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
                        p2p_dbg(p2p, "Provision Discovery Request add device failed "
                                MACSTR, MAC2STR(sa));
                        goto out;
@@ -665,29 +661,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                                MACSTR, MAC2STR(sa));
                        goto out;
                }
-       } else if (msg.wfd_subelems) {
+       } else if (msg->wfd_subelems) {
                wpabuf_free(dev->info.wfd_subelems);
-               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
        }
 
-       p2p_update_peer_6ghz_capab(dev, &msg);
+       p2p_update_peer_6ghz_capab(dev, msg);
 
-       if (!msg.adv_id) {
+       if (!msg->adv_id) {
                allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
-               if (!(msg.wps_config_methods & allowed_config_methods)) {
+               if (!(msg->wps_config_methods & allowed_config_methods)) {
                        p2p_dbg(p2p,
                                "Unsupported Config Methods in Provision Discovery Request");
                        goto out;
                }
 
                /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
-               if (msg.group_id) {
+               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))
+                                           msg->group_id, msg->group_id_len))
                                        break;
                        }
                        if (i == p2p->num_groups) {
@@ -703,29 +699,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                 * Set adv_id here, so in case of an error, a P2PS PD Response
                 * will be sent.
                 */
-               adv_id = WPA_GET_LE32(msg.adv_id);
-               if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
+               adv_id = WPA_GET_LE32(msg->adv_id);
+               if (p2ps_validate_pd_req(p2p, msg, sa) < 0) {
                        reject = P2P_SC_FAIL_INVALID_PARAMS;
                        goto out;
                }
 
-               req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+               req_fcap = (struct p2ps_feature_capab *) msg->feature_cap;
 
-               os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
-               os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+               os_memcpy(session_mac, msg->session_mac, ETH_ALEN);
+               os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
 
-               session_id = WPA_GET_LE32(msg.session_id);
+               session_id = WPA_GET_LE32(msg->session_id);
 
-               if (msg.conn_cap)
-                       conncap = *msg.conn_cap;
+               if (msg->conn_cap)
+                       conncap = *msg->conn_cap;
 
                /*
                 * We need to verify a P2PS config methog in an initial PD
                 * request or in a follow-on PD request with the status
                 * SUCCESS_DEFERRED.
                 */
-               if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
-                   !(msg.wps_config_methods & allowed_config_methods)) {
+               if ((!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) &&
+                   !(msg->wps_config_methods & allowed_config_methods)) {
                        p2p_dbg(p2p,
                                "Unsupported Config Methods in Provision Discovery Request");
                        goto out;
@@ -741,18 +737,18 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        P2P_DEV_PD_PEER_KEYPAD |
                        P2P_DEV_PD_PEER_P2PS);
 
-       if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
+       if (msg->wps_config_methods & WPS_CONFIG_DISPLAY) {
                p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to show a PIN on display", MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
                passwd_id = DEV_PW_USER_SPECIFIED;
-       } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+       } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
                p2p_dbg(p2p, "Peer " MACSTR
                        " requested us to write its PIN using keypad",
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
                passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
-       } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+       } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
                p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_P2PS;
@@ -763,8 +759,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        if (p2p->cfg->remove_stale_groups) {
                p2p->cfg->remove_stale_groups(
                        p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
-                       msg.persistent_dev,
-                       msg.persistent_ssid, msg.persistent_ssid_len);
+                       msg->persistent_dev,
+                       msg->persistent_ssid, msg->persistent_ssid_len);
        }
 
        reject = P2P_SC_SUCCESS;
@@ -773,15 +769,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
         * End of a legacy P2P PD Request processing, from this point continue
         * with P2PS one.
         */
-       if (!msg.adv_id)
+       if (!msg->adv_id)
                goto out;
 
        remote_conncap = conncap;
 
-       if (!msg.status) {
+       if (!msg->status) {
                unsigned int forced_freq, pref_freq;
 
-               if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) {
+               if (!ether_addr_equal(p2p->cfg->dev_addr, msg->adv_mac)) {
                        p2p_dbg(p2p,
                                "P2PS PD adv mac does not match the local one");
                        reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
@@ -818,12 +814,12 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                                "Incompatible P2PS feature capability CPT bitmask");
                        reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
                } else if (p2ps_adv->config_methods &&
-                          !(msg.wps_config_methods &
+                          !(msg->wps_config_methods &
                             p2ps_adv->config_methods)) {
                        p2p_dbg(p2p,
                                "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
                                p2ps_adv->config_methods,
-                               msg.wps_config_methods);
+                               msg->wps_config_methods);
                        reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
                } else if (!p2ps_adv->state) {
                        p2p_dbg(p2p, "P2PS state unavailable");
@@ -833,24 +829,24 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
                }
 
-               if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+               if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
                        p2p_dbg(p2p, "Keypad - always defer");
                        auto_accept = 0;
                }
 
                if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
-                    msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
-                   msg.channel_list && msg.channel_list_len &&
+                    msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
+                   msg->channel_list && msg->channel_list_len &&
                    p2p_peer_channels_check(p2p, &p2p->channels, dev,
-                                           msg.channel_list,
-                                           msg.channel_list_len) < 0) {
+                                           msg->channel_list,
+                                           msg->channel_list_len) < 0) {
                        p2p_dbg(p2p,
                                "No common channels - force deferred flow");
                        auto_accept = 0;
                }
 
                if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
-                    msg.persistent_dev) && msg.operating_channel) {
+                    msg->persistent_dev) && msg->operating_channel) {
                        struct p2p_channels intersect;
 
                        /*
@@ -861,15 +857,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                         */
                        if (dev->channels.reg_classes == 0 ||
                            !p2p_channels_includes(&dev->channels,
-                                                  msg.operating_channel[3],
-                                                  msg.operating_channel[4])) {
+                                                  msg->operating_channel[3],
+                                                  msg->operating_channel[4])) {
                                struct p2p_channels *ch = &dev->channels;
 
                                os_memset(ch, 0, sizeof(*ch));
                                ch->reg_class[0].reg_class =
-                                       msg.operating_channel[3];
+                                       msg->operating_channel[3];
                                ch->reg_class[0].channel[0] =
-                                       msg.operating_channel[4];
+                                       msg->operating_channel[4];
                                ch->reg_class[0].channels = 1;
                                ch->reg_classes = 1;
                        }
@@ -888,7 +884,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        struct p2ps_provision *tmp;
 
                        if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
-                                                msg.wps_config_methods,
+                                                msg->wps_config_methods,
                                                 session_mac, adv_mac) < 0) {
                                reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
                                goto out;
@@ -910,7 +906,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                }
        }
 
-       if (!msg.status && !auto_accept &&
+       if (!msg->status && !auto_accept &&
            (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
                struct p2ps_provision *tmp;
 
@@ -920,7 +916,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                }
 
                if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
-                                        msg.wps_config_methods,
+                                        msg->wps_config_methods,
                                         session_mac, adv_mac) < 0) {
                        reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
                        goto out;
@@ -931,26 +927,26 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        }
 
        /* Not a P2PS Follow-on PD */
-       if (!msg.status)
+       if (!msg->status)
                goto out;
 
-       if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
-               reject = *msg.status;
+       if (*msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) {
+               reject = *msg->status;
                goto out;
        }
 
-       if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
+       if (*msg->status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
                goto out;
 
        if (p2p->p2ps_prov->adv_id != adv_id ||
-           !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) {
+           !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) {
                p2p_dbg(p2p,
                        "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
                goto out;
        }
 
        if (p2p->p2ps_prov->session_id != session_id ||
-           !ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) {
+           !ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) {
                p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
                goto out;
        }
@@ -981,7 +977,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        else if (method & WPS_CONFIG_KEYPAD)
                method = WPS_CONFIG_DISPLAY;
 
-       if (!conncap || !(msg.wps_config_methods & method)) {
+       if (!conncap || !(msg->wps_config_methods & method)) {
                /*
                 * Reject this "Deferred Accept*
                 * if incompatible conncap or method
@@ -992,11 +988,11 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        "Incompatible P2PS feature capability CPT bitmask");
                reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
        } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
-                   msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
-                  msg.channel_list && msg.channel_list_len &&
+                   msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
+                  msg->channel_list && msg->channel_list_len &&
                   p2p_peer_channels_check(p2p, &p2p->channels, dev,
-                                          msg.channel_list,
-                                          msg.channel_list_len) < 0) {
+                                          msg->channel_list,
+                                          msg->channel_list_len) < 0) {
                p2p_dbg(p2p,
                        "No common channels in Follow-On Provision Discovery Request");
                reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@@ -1008,10 +1004,10 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
        if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
                u8 tmp;
 
-               if (msg.operating_channel)
+               if (msg->operating_channel)
                        dev->oper_freq =
-                               p2p_channel_to_freq(msg.operating_channel[3],
-                                                   msg.operating_channel[4]);
+                               p2p_channel_to_freq(msg->operating_channel[3],
+                                                   msg->operating_channel[4]);
 
                if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
                    p2p_go_select_channel(p2p, dev, &tmp) < 0)
@@ -1024,7 +1020,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 out:
        if (reject == P2P_SC_SUCCESS ||
            reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
-               config_methods = msg.wps_config_methods;
+               config_methods = msg->wps_config_methods;
        else
                config_methods = 0;
 
@@ -1032,18 +1028,18 @@ out:
         * Send PD Response for an initial PD Request or for follow-on
         * PD Request with P2P_SC_SUCCESS_DEFERRED status.
         */
-       if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
-               resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token,
+       if (!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) {
+               resp = p2p_build_prov_disc_resp(p2p, dev, msg->dialog_token,
                                                reject, config_methods, adv_id,
-                                               msg.group_id, msg.group_id_len,
-                                               msg.persistent_ssid,
-                                               msg.persistent_ssid_len,
+                                               msg->group_id,
+                                               msg->group_id_len,
+                                               msg->persistent_ssid,
+                                               msg->persistent_ssid_len,
                                                (const u8 *) &resp_fcap,
                                                sizeof(resp_fcap));
-               if (!resp) {
-                       p2p_parse_free(&msg);
+               if (!resp)
                        return;
-               }
+
                p2p_dbg(p2p, "Sending Provision Discovery Response");
                if (rx_freq > 0)
                        freq = rx_freq;
@@ -1053,7 +1049,6 @@ out:
                if (freq < 0) {
                        p2p_dbg(p2p, "Unknown regulatory class/channel");
                        wpabuf_free(resp);
-                       p2p_parse_free(&msg);
                        return;
                }
                p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
@@ -1068,10 +1063,8 @@ out:
                wpabuf_free(resp);
        }
 
-       if (!dev) {
-               p2p_parse_free(&msg);
+       if (!dev)
                return;
-       }
 
        freq = 0;
        if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
@@ -1083,17 +1076,17 @@ out:
 
        if (!p2p->cfg->p2ps_prov_complete) {
                /* Don't emit anything */
-       } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
-                  *msg.status != P2P_SC_SUCCESS_DEFERRED) {
-               reject = *msg.status;
+       } else if (msg->status && *msg->status != P2P_SC_SUCCESS &&
+                  *msg->status != P2P_SC_SUCCESS_DEFERRED) {
+               reject = *msg->status;
                p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
                                             sa, adv_mac, session_mac,
                                             NULL, adv_id, session_id,
-                                            0, 0, msg.persistent_ssid,
-                                            msg.persistent_ssid_len,
+                                            0, 0, msg->persistent_ssid,
+                                            msg->persistent_ssid_len,
                                             0, 0, NULL, NULL, 0, freq,
                                             NULL, 0);
-       } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+       } else if (msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
                   p2p->p2ps_prov) {
                p2p->p2ps_prov->status = reject;
                p2p->p2ps_prov->conncap = conncap;
@@ -1103,77 +1096,77 @@ out:
                                                     sa, adv_mac, session_mac,
                                                     NULL, adv_id,
                                                     session_id, conncap, 0,
-                                                    msg.persistent_ssid,
-                                                    msg.persistent_ssid_len, 0,
-                                                    0, NULL, NULL, 0, freq,
+                                                    msg->persistent_ssid,
+                                                    msg->persistent_ssid_len,
+                                                    0, 0, NULL, NULL, 0, freq,
                                                     NULL, 0);
                else
                        p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
-                                                    *msg.status,
+                                                    *msg->status,
                                                     sa, adv_mac, session_mac,
                                                     group_mac, adv_id,
                                                     session_id, conncap,
                                                     passwd_id,
-                                                    msg.persistent_ssid,
-                                                    msg.persistent_ssid_len, 0,
-                                                    0, NULL,
+                                                    msg->persistent_ssid,
+                                                    msg->persistent_ssid_len,
+                                                    0, 0, NULL,
                                                     (const u8 *) &resp_fcap,
                                                     sizeof(resp_fcap), freq,
                                                     NULL, 0);
-       } else if (msg.status && p2p->p2ps_prov) {
+       } else if (msg->status && p2p->p2ps_prov) {
                p2p->p2ps_prov->status = P2P_SC_SUCCESS;
-               p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
+               p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg->status, sa,
                                             adv_mac, session_mac, group_mac,
                                             adv_id, session_id, conncap,
                                             passwd_id,
-                                            msg.persistent_ssid,
-                                            msg.persistent_ssid_len,
+                                            msg->persistent_ssid,
+                                            msg->persistent_ssid_len,
                                             0, 0, NULL,
                                             (const u8 *) &resp_fcap,
                                             sizeof(resp_fcap), freq, NULL, 0);
-       } else if (msg.status) {
+       } else if (msg->status) {
        } else if (auto_accept && reject == P2P_SC_SUCCESS) {
                p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
                                             sa, adv_mac, session_mac,
                                             group_mac, adv_id, session_id,
                                             conncap, passwd_id,
-                                            msg.persistent_ssid,
-                                            msg.persistent_ssid_len,
+                                            msg->persistent_ssid,
+                                            msg->persistent_ssid_len,
                                             0, 0, NULL,
                                             (const u8 *) &resp_fcap,
                                             sizeof(resp_fcap), freq,
-                                            msg.group_id ?
-                                            msg.group_id + ETH_ALEN : NULL,
-                                            msg.group_id ?
-                                            msg.group_id_len - ETH_ALEN : 0);
+                                            msg->group_id ?
+                                            msg->group_id + ETH_ALEN : NULL,
+                                            msg->group_id ?
+                                            msg->group_id_len - ETH_ALEN : 0);
        } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
-                  (!msg.session_info || !msg.session_info_len)) {
-               p2p->p2ps_prov->method = msg.wps_config_methods;
+                  (!msg->session_info || !msg->session_info_len)) {
+               p2p->p2ps_prov->method = msg->wps_config_methods;
 
                p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
                                             sa, adv_mac, session_mac,
                                             group_mac, adv_id, session_id,
                                             conncap, passwd_id,
-                                            msg.persistent_ssid,
-                                            msg.persistent_ssid_len,
+                                            msg->persistent_ssid,
+                                            msg->persistent_ssid_len,
                                             0, 1, NULL,
                                             (const u8 *) &resp_fcap,
                                             sizeof(resp_fcap), freq, NULL, 0);
        } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
-               size_t buf_len = msg.session_info_len;
+               size_t buf_len = msg->session_info_len;
                char *buf = os_malloc(2 * buf_len + 1);
 
                if (buf) {
-                       p2p->p2ps_prov->method = msg.wps_config_methods;
+                       p2p->p2ps_prov->method = msg->wps_config_methods;
 
-                       utf8_escape((char *) msg.session_info, buf_len,
+                       utf8_escape((char *) msg->session_info, buf_len,
                                    buf, 2 * buf_len + 1);
 
                        p2p->cfg->p2ps_prov_complete(
                                p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
                                adv_mac, session_mac, group_mac, adv_id,
                                session_id, conncap, passwd_id,
-                               msg.persistent_ssid, msg.persistent_ssid_len,
+                               msg->persistent_ssid, msg->persistent_ssid_len,
                                0, 1, buf,
                                (const u8 *) &resp_fcap, sizeof(resp_fcap),
                                freq, NULL, 0);
@@ -1201,29 +1194,30 @@ out:
         *    seeker: KEYPAD, response status: SUCCESS
         */
        if (p2p->cfg->prov_disc_req &&
-           ((reject == P2P_SC_SUCCESS && !msg.adv_id) ||
-            (!msg.status &&
+           ((reject == P2P_SC_SUCCESS && !msg->adv_id) ||
+            (!msg->status &&
             (reject == P2P_SC_SUCCESS ||
              reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) &&
              passwd_id == DEV_PW_USER_SPECIFIED) ||
-            (!msg.status &&
+            (!msg->status &&
              reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
              passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
             (reject == P2P_SC_SUCCESS &&
-             msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+             msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
               passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) {
                const u8 *dev_addr = sa;
 
-               if (msg.p2p_device_addr)
-                       dev_addr = msg.p2p_device_addr;
+               if (msg->p2p_device_addr)
+                       dev_addr = msg->p2p_device_addr;
                p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
-                                       msg.wps_config_methods,
-                                       dev_addr, msg.pri_dev_type,
-                                       msg.device_name, msg.config_methods,
-                                       msg.capability ? msg.capability[0] : 0,
-                                       msg.capability ? msg.capability[1] :
+                                       msg->wps_config_methods,
+                                       dev_addr, msg->pri_dev_type,
+                                       msg->device_name, msg->config_methods,
+                                       msg->capability ? msg->capability[0] :
                                        0,
-                                       msg.group_id, msg.group_id_len);
+                                       msg->capability ? msg->capability[1] :
+                                       0,
+                                       msg->group_id, msg->group_id_len);
        }
 
        if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
@@ -1248,10 +1242,22 @@ out:
                        break;
                }
 
-               if (msg.intended_addr)
-                       os_memcpy(dev->interface_addr, msg.intended_addr,
+               if (msg->intended_addr)
+                       os_memcpy(dev->interface_addr, msg->intended_addr,
                                  ETH_ALEN);
        }
+}
+
+
+void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+                             const u8 *data, size_t len, int rx_freq)
+{
+       struct p2p_message msg;
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, rx_freq);
        p2p_parse_free(&msg);
 }
 
@@ -1354,10 +1360,10 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p,
 }
 
 
-void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
-                               const u8 *data, size_t len)
+static void p2p_process_prov_disc_resp(struct p2p_data *p2p,
+                                      struct p2p_message *msg, const u8 *sa,
+                                      const u8 *data, size_t len)
 {
-       struct p2p_message msg;
        struct p2p_device *dev;
        u16 report_config_methods = 0, req_config_methods;
        u8 status = P2P_SC_SUCCESS;
@@ -1368,30 +1374,25 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        int passwd_id = DEV_PW_DEFAULT;
        int p2ps_seeker;
 
-       if (p2p_parse(data, len, &msg))
+       if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, msg))
                return;
 
-       if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
-               p2p_parse_free(&msg);
-               return;
-       }
-
        /* Parse the P2PS members present */
-       if (msg.status)
-               status = *msg.status;
+       if (msg->status)
+               status = *msg->status;
 
-       group_mac = msg.intended_addr;
+       group_mac = msg->intended_addr;
 
-       if (msg.adv_mac)
-               os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+       if (msg->adv_mac)
+               os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
        else
                os_memset(adv_mac, 0, ETH_ALEN);
 
-       if (msg.adv_id)
-               adv_id = WPA_GET_LE32(msg.adv_id);
+       if (msg->adv_id)
+               adv_id = WPA_GET_LE32(msg->adv_id);
 
-       if (msg.conn_cap) {
-               conncap = *msg.conn_cap;
+       if (msg->conn_cap) {
+               conncap = *msg->conn_cap;
 
                /* Switch bits to local relative */
                switch (conncap) {
@@ -1406,25 +1407,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
 
        p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
                " with config methods 0x%x",
-               MAC2STR(sa), msg.wps_config_methods);
+               MAC2STR(sa), msg->wps_config_methods);
 
        dev = p2p_get_device(p2p, sa);
        if (dev == NULL || !dev->req_config_methods) {
                p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
                        " with no pending request", MAC2STR(sa));
-               p2p_parse_free(&msg);
                return;
-       } else if (msg.wfd_subelems) {
+       } else if (msg->wfd_subelems) {
                wpabuf_free(dev->info.wfd_subelems);
-               dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+               dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
        }
 
-       p2p_update_peer_6ghz_capab(dev, &msg);
+       p2p_update_peer_6ghz_capab(dev, msg);
 
-       if (dev->dialog_token != msg.dialog_token) {
+       if (dev->dialog_token != msg->dialog_token) {
                p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
-                       msg.dialog_token, dev->dialog_token);
-               p2p_parse_free(&msg);
+                       msg->dialog_token, dev->dialog_token);
                return;
        }
 
@@ -1449,14 +1448,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
            ether_addr_equal(p2p->pending_pd_devaddr, sa))
                p2p_reset_pending_pd(p2p);
 
-       if (msg.wps_config_methods != req_config_methods) {
+       if (msg->wps_config_methods != req_config_methods) {
                p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
-                       msg.wps_config_methods, req_config_methods);
+                       msg->wps_config_methods, req_config_methods);
                if (p2p->cfg->prov_disc_fail)
                        p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
                                                 P2P_PROV_DISC_REJECTED,
                                                 adv_id, adv_mac, NULL);
-               p2p_parse_free(&msg);
                p2ps_prov_free(p2p);
                goto out;
        }
@@ -1470,13 +1468,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                        " accepted to show a PIN on display", MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
                passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
-       } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+       } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
                p2p_dbg(p2p, "Peer " MACSTR
                        " accepted to write our PIN using keypad",
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
                passwd_id = DEV_PW_USER_SPECIFIED;
-       } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+       } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
                p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
                        MAC2STR(sa));
                dev->flags |= P2P_DEV_PD_PEER_P2PS;
@@ -1495,23 +1493,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                 * fails the flow would continue, although it would probably
                 * fail. Same is true for the operating channel.
                 */
-               if (msg.channel_list && msg.channel_list_len &&
+               if (msg->channel_list && msg->channel_list_len &&
                    p2p_peer_channels_check(p2p, &p2p->channels, dev,
-                                           msg.channel_list,
-                                           msg.channel_list_len) < 0)
+                                           msg->channel_list,
+                                           msg->channel_list_len) < 0)
                        p2p_dbg(p2p, "P2PS PD Response - no common channels");
 
-               if (msg.operating_channel) {
+               if (msg->operating_channel) {
                        if (p2p_channels_includes(&p2p->channels,
-                                                 msg.operating_channel[3],
-                                                 msg.operating_channel[4]) &&
+                                                 msg->operating_channel[3],
+                                                 msg->operating_channel[4]) &&
                            p2p_channels_includes(&dev->channels,
-                                                 msg.operating_channel[3],
-                                                 msg.operating_channel[4])) {
+                                                 msg->operating_channel[3],
+                                                 msg->operating_channel[4])) {
                                dev->oper_freq =
                                        p2p_channel_to_freq(
-                                               msg.operating_channel[3],
-                                               msg.operating_channel[4]);
+                                               msg->operating_channel[3],
+                                               msg->operating_channel[4]);
                        } else {
                                p2p_dbg(p2p,
                                        "P2PS PD Response - invalid operating channel");
@@ -1543,11 +1541,12 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                                p2p->cfg->cb_ctx, status, sa, adv_mac,
                                p2p->p2ps_prov->session_mac,
                                group_mac, adv_id, p2p->p2ps_prov->session_id,
-                               conncap, passwd_id, msg.persistent_ssid,
-                               msg.persistent_ssid_len, 1, 0, NULL,
-                               msg.feature_cap, msg.feature_cap_len, freq,
-                               msg.group_id ? msg.group_id + ETH_ALEN : NULL,
-                               msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
+                               conncap, passwd_id, msg->persistent_ssid,
+                               msg->persistent_ssid_len, 1, 0, NULL,
+                               msg->feature_cap, msg->feature_cap_len, freq,
+                               msg->group_id ? msg->group_id + ETH_ALEN : NULL,
+                               msg->group_id ? msg->group_id_len - ETH_ALEN :
+                               0);
                }
                p2ps_prov_free(p2p);
        } else if (status != P2P_SC_SUCCESS &&
@@ -1569,16 +1568,15 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                                                      NULL, NULL, 0);
                }
 
-               if (msg.session_info && msg.session_info_len) {
-                       size_t info_len = msg.session_info_len;
+               if (msg->session_info && msg->session_info_len) {
+                       size_t info_len = msg->session_info_len;
                        char *deferred_sess_resp = os_malloc(2 * info_len + 1);
 
                        if (!deferred_sess_resp) {
-                               p2p_parse_free(&msg);
                                p2ps_prov_free(p2p);
                                goto out;
                        }
-                       utf8_escape((char *) msg.session_info, info_len,
+                       utf8_escape((char *) msg->session_info, info_len,
                                    deferred_sess_resp, 2 * info_len + 1);
 
                        if (p2p->cfg->prov_disc_fail)
@@ -1600,17 +1598,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
                        p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
                                                 P2P_PROV_DISC_REJECTED,
                                                 adv_id, adv_mac, NULL);
-               p2p_parse_free(&msg);
                p2ps_prov_free(p2p);
                goto out;
        }
 
        /* Store the provisioning info */
-       dev->wps_prov_info = msg.wps_config_methods;
-       if (msg.intended_addr)
-               os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN);
-
-       p2p_parse_free(&msg);
+       dev->wps_prov_info = msg->wps_config_methods;
+       if (msg->intended_addr)
+               os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN);
 
 out:
        dev->req_config_methods = 0;
@@ -1654,6 +1649,19 @@ out:
 }
 
 
+void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
+                              const u8 *data, size_t len)
+{
+       struct p2p_message msg;
+
+       if (p2p_parse(data, len, &msg))
+               return;
+
+       p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1);
+       p2p_parse_free(&msg);
+}
+
+
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
                           int join, int force_freq)
 {