[PATCH 23/34] PR: Add support to handle PR IE in Auth M2 and prepare M3

Peddolla Harshavardhan Reddy peddolla at qti.qualcomm.com
Thu Jun 19 08:37:16 PDT 2025


PASN Auth M2 frame is processed and then M3 is prepared based on the
operation mode received in M2 and capabilities received in M2 are also
validated. If a operation mode could not be decided or validation of
capabilities has failed, Then status is set as failure and M3 is sent.
If PR capabilities are valid and operation mode received in M2 can be
honored then status is set as success and operation mode is set in
M3.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla at qti.qualcomm.com>
---
 src/common/proximity_ranging.c | 187 +++++++++++++++++++++++++++++++++
 1 file changed, 187 insertions(+)

diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c
index 99b481799..ea002f8c5 100644
--- a/src/common/proximity_ranging.c
+++ b/src/common/proximity_ranging.c
@@ -1320,6 +1320,136 @@ static u8 pr_pasn_get_best_op_mode(struct pr_data *pr, u8 supp_roles,
 }
 
 
+static void pr_choose_best_channel(struct pr_channels *common_channel,
+				   u8 *op_class, u8 *op_channel)
+{
+	*op_class = common_channel->op_class[0].op_class;
+	*op_channel = common_channel->op_class[0].channel[0];
+}
+
+
+static u8 pr_pasn_get_final_op_mode(struct pr_data *pr, u8 supp_roles,
+				     struct operation_mode *op_mode,
+				     struct operation_mode *res_op_mode)
+{
+	u8 status = PR_NEGOTIATION_FAIL;
+	u8 op_class, op_channel;
+	struct pr_channels common_chan;
+
+	if (op_mode->protocol_type & PR_NTB_SECURE_LTF_BASED_RANGING ||
+	    op_mode->protocol_type & PR_NTB_OPEN_BASED_RANGING) {
+		if (!pr->cfg->ntb_ista_support && !pr->cfg->ntb_rsta_support) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: Device can't fulfill requested NTB Role");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		if (op_mode->protocol_type & PR_NTB_SECURE_LTF_BASED_RANGING &&
+		    !pr->cfg->secure_he_ltf) {
+			wpa_printf(MSG_DEBUG, "PR: Secure HE-LTF not supported");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		pr_channels_intersect(&pr->cfg->ntb_channels,
+				      &op_mode->channels, &common_chan);
+		if (!common_chan.op_classes) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: No common channels to perform ranging");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		pr_choose_best_channel(&common_chan, &op_class, &op_channel);
+		if (!op_class || !op_channel) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: Couldn't choose a common channel for ranging");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		if (op_mode->role == PR_ISTA_SUPPORT &&
+		    !pr->cfg->ntb_rsta_support &&
+		    !(supp_roles & PR_RSTA_SUPPORT)) {
+			wpa_printf(MSG_DEBUG, "PR: Device cannot act as NTB RSTA");
+			return PR_NEGOTIATION_FAIL;
+		} else if (op_mode->role == PR_RSTA_SUPPORT &&
+			   !pr->cfg->ntb_ista_support &&
+			   !(supp_roles & PR_ISTA_SUPPORT)) {
+			wpa_printf(MSG_DEBUG, "PR: Device cannot act as NTB ISTA");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		if (op_mode->role == PR_ISTA_SUPPORT &&
+		    pr->cfg->ntb_rsta_support) {
+			res_op_mode->role = PR_RSTA_SUPPORT;
+			status = PR_NEGOTIATION_SUCCESS;
+		} else if (op_mode->role == PR_RSTA_SUPPORT &&
+			   pr->cfg->ntb_ista_support) {
+			res_op_mode->role = PR_ISTA_SUPPORT;
+			status = PR_NEGOTIATION_SUCCESS;
+		}
+
+		res_op_mode->protocol_type = op_mode->protocol_type;
+		os_memcpy(res_op_mode->country, pr->cfg->country, 3);
+		res_op_mode->channels.op_classes = 1;
+		res_op_mode->channels.op_class[0].channels = 1;
+		res_op_mode->channels.op_class[0].channel[0] = op_channel;
+		res_op_mode->channels.op_class[0].op_class = op_class;
+
+		return status;
+	} else if (op_mode->protocol_type & PR_EDCA_BASED_RANGING) {
+		if (!pr->cfg->edca_ista_support &&
+		    !pr->cfg->edca_rsta_support) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: Device can't fulfill EDCA role");
+			return PR_NEGOTIATION_FAIL;
+		}
+		pr_channels_intersect(&pr->cfg->edca_channels,
+				      &op_mode->channels, &common_chan);
+		if (!common_chan.op_classes) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: No common channels to perform ranging");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		pr_choose_best_channel(&common_chan, &op_class, &op_channel);
+		if (!op_class || !op_channel) {
+			wpa_printf(MSG_DEBUG,
+				   "PR: Couldn't choose a common channel for ranging");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		if (op_mode->role == PR_ISTA_SUPPORT &&
+		    !pr->cfg->edca_rsta_support &&
+		    !(supp_roles & PR_RSTA_SUPPORT)) {
+			wpa_printf(MSG_DEBUG, "PR: Device cannot act as NTB RSTA");
+			return PR_NEGOTIATION_FAIL;
+		} else if (op_mode->role == PR_RSTA_SUPPORT &&
+			   !pr->cfg->edca_ista_support &&
+			   !(supp_roles & PR_ISTA_SUPPORT)) {
+			wpa_printf(MSG_DEBUG, "PR: Device cannot act as NTB ISTA");
+			return PR_NEGOTIATION_FAIL;
+		}
+
+		if (op_mode->role == PR_ISTA_SUPPORT &&
+		    pr->cfg->edca_rsta_support) {
+			res_op_mode->role = PR_RSTA_SUPPORT;
+			status = PR_NEGOTIATION_SUCCESS;
+		} else if (op_mode->role == PR_RSTA_SUPPORT &&
+			   pr->cfg->edca_ista_support) {
+			res_op_mode->role = PR_ISTA_SUPPORT;
+			status = PR_NEGOTIATION_SUCCESS;
+		}
+
+		res_op_mode->protocol_type = op_mode->protocol_type;
+		os_memcpy(res_op_mode->country, pr->cfg->country, 3);
+		res_op_mode->channels.op_classes = 1;
+		res_op_mode->channels.op_class[0].channels = 1;
+		res_op_mode->channels.op_class[0].channel[0] = op_channel;
+		res_op_mode->channels.op_class[0].op_class = op_class;
+	}
+	return status;
+}
+
+
 static int pr_prepare_pasn_pr_ie(struct pr_data *pr, struct wpabuf *extra_ies,
 				 bool add_dira, u8 ranging_role,
 				 u8 ranging_type, int forced_pr_freq)
@@ -1815,6 +1945,20 @@ static int pr_process_pasn_ranging_wrapper(struct pr_data *pr,
 		goto end;
 	}
 
+	if (trans_seq == 2) {
+		if (!msg.status_ie || !msg.status_ie_len) {
+			wpa_printf(MSG_DEBUG, "PR PASN: * No status attribute");
+			wpabuf_free(buf);
+			return -1;
+		}
+		if (*msg.status_ie == PR_NEGOTIATION_FAIL) {
+			wpa_printf(MSG_DEBUG,
+				   "PR PASN: * Ranging Negotiation status fail");
+			wpabuf_free(buf);
+			return -1;
+		}
+	}
+
 	if (msg.dira && msg.dira_len)
 		pr_validate_dira(pr, dev, msg.dira, msg.dira_len);
 
@@ -1878,6 +2022,9 @@ static int pr_process_pasn_ranging_wrapper(struct pr_data *pr,
 	if (trans_seq == 1)
 		status = pr_pasn_get_best_op_mode(pr, supp_ranging_role,
 						  &op_mode, &res_op_mode);
+	else if (trans_seq == 2)
+		status = pr_pasn_get_final_op_mode(pr, supp_ranging_role,
+						   &op_mode, &res_op_mode);
 
 	if (status != PR_NEGOTIATION_SUCCESS &&
 	    status != PR_NEGOTIATION_UPDATE) {
@@ -1985,6 +2132,44 @@ fail:
 }
 
 
+static int pr_pasn_handle_auth_2(struct pr_data *pr, struct pr_device *dev,
+				 const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	int ret = -1;
+	struct wpa_pasn_params_data pasn_data;
+
+	if (dev->pasn_role != PR_ROLE_PASN_INITIATOR) {
+		wpa_printf(MSG_ERROR, "PR PASN: Auth2 not expected on responder");
+		return -1;
+	}
+
+	if (!dev->pasn)
+		return -1;
+
+	if (pr_process_pasn_ranging_wrapper(pr, dev, mgmt, len, 2)) {
+		wpa_printf(MSG_ERROR,
+			   "PR PASN: Handle Auth2 action wrapper failed");
+		return -1;
+	}
+	pasn_set_extra_ies(dev->pasn, wpabuf_head_u8(dev->ranging_wrapper),
+			   wpabuf_len(dev->ranging_wrapper));
+
+	if (wpa_pasn_auth_rx(dev->pasn, (const u8 *) mgmt, len,
+			     &pasn_data) < 0) {
+		wpa_printf(MSG_ERROR, "PR PASN: wpa_pasn_auth_rx() failed");
+		dev->pasn_role = PR_ROLE_IDLE;
+		goto fail;
+	}
+
+	ret = 0;
+
+fail:
+	wpabuf_free(dev->ranging_wrapper);
+	dev->ranging_wrapper = NULL;
+	return ret;
+}
+
+
 int pr_pasn_auth_rx(struct pr_data *pr, const struct ieee80211_mgmt *mgmt,
 		    size_t len, int freq)
 {
@@ -2017,6 +2202,8 @@ int pr_pasn_auth_rx(struct pr_data *pr, const struct ieee80211_mgmt *mgmt,
 
 	if (auth_transaction == 1)
 		return pr_pasn_handle_auth_1(pr, dev, mgmt, len, freq);
+	else if (auth_transaction == 2)
+		return pr_pasn_handle_auth_2(pr, dev, mgmt, len);
 	return -1;
 }
 
-- 
2.34.1




More information about the Hostap mailing list