diff mbox series

[06/13] P2P: Cleanup of provision discovery req and resp processing

Message ID 1720431149-7494-6-git-send-email-quic_shivbara@quicinc.com
State Superseded
Headers show
Series [01/13] NAN: Option to offload NAN DE for USD into the driver | expand

Commit Message

Shivani Baranwal July 8, 2024, 9:32 a.m. UTC
Parse the p2p ies in handle provision discovery req and response
functions and process the frames based on the ies received in the
pd frames.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
diff mbox series

Patch

diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index aa6e8ed61..0a5c35ff5 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1925,10 +1925,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);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 787e599ca..2b1087744 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -884,10 +884,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);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 539b61aa4..ea4dcfd26 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -597,10 +597,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;
@@ -621,13 +621,10 @@  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)) {
@@ -648,29 +645,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) {
@@ -686,29 +683,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;
@@ -724,18 +721,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;
@@ -746,8 +743,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;
@@ -756,15 +753,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;
@@ -801,12 +798,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");
@@ -816,24 +813,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;
 
 			/*
@@ -844,15 +841,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;
 			}
@@ -871,7 +868,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;
@@ -893,7 +890,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;
 
@@ -903,7 +900,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;
@@ -914,26 +911,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;
 	}
@@ -964,7 +961,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
@@ -975,11 +972,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;
@@ -991,10 +988,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)
@@ -1007,7 +1004,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;
 
@@ -1015,18 +1012,17 @@  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;
@@ -1036,7 +1032,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;
@@ -1051,10 +1046,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) {
@@ -1066,17 +1059,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;
@@ -1086,77 +1079,77 @@  out:
 						     sa, adv_mac, session_mac,
 						     NULL, adv_id,
 						     session_id, conncap, 0,
-						     msg.persistent_ssid,
-						     msg.persistent_ssid_len, 0,
+						     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,
+						     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);
@@ -1184,29 +1177,29 @@  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->capability ? msg->capability[1] :
 					0,
-					msg.group_id, msg.group_id_len);
+					msg->group_id, msg->group_id_len);
 	}
 
 	if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
@@ -1231,10 +1224,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);
 }
 
@@ -1337,10 +1342,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;
@@ -1351,30 +1356,26 @@  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))
-		return;
-
-	if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
-		p2p_parse_free(&msg);
+	if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, 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) {
@@ -1389,25 +1390,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;
 	}
 
@@ -1432,14 +1431,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;
 	}
@@ -1453,13 +1451,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;
@@ -1478,23 +1476,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");
@@ -1526,11 +1524,11 @@  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 &&
@@ -1552,16 +1550,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)
@@ -1583,17 +1580,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;
@@ -1637,6 +1631,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)
 {