[PATCH 53/92] NAN: Parse PMKIDs from the SCIA in publish messages

Andrei Otcheretianski andrei.otcheretianski at intel.com
Wed Apr 22 05:23:44 PDT 2026


From: Avraham Stern <avraham.stern at intel.com>

If the publish message includes a Security Context Information
attribute with a list of PMKIDs, parse the PMKIDs associated with
the service and add them to the discovery result notification.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 src/ap/nan_usd_ap.c             |  3 +-
 src/common/nan_de.c             | 80 +++++++++++++++++++++++++++++++--
 src/common/nan_de.h             |  3 +-
 wpa_supplicant/nan_supplicant.c |  3 +-
 4 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c
index 34f268d880..d7719e89cb 100644
--- a/src/ap/nan_usd_ap.c
+++ b/src/ap/nan_usd_ap.c
@@ -48,7 +48,8 @@ hostapd_nan_de_discovery_result(void *ctx, int subscribe_id,
 				enum nan_service_protocol_type srv_proto_type,
 				const u8 *ssi, size_t ssi_len,
 				int peer_publish_id, const u8 *peer_addr,
-				bool fsd, bool fsd_gas)
+				bool fsd, bool fsd_gas,
+				const u8 *pmkid_list, size_t pmkid_count)
 {
 	struct hostapd_data *hapd = ctx;
 	char *ssi_hex;
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 779e3f11aa..7a728c45b5 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -1132,6 +1132,66 @@ static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id,
 }
 
 
+static size_t nan_de_parse_scia(const u8 *buf, size_t len, u8 instance_id,
+				u8 *pmkid_list, size_t max_pmkids)
+{
+	const u8 *scia, *end;
+	u16 scia_len;
+	size_t pmkid_count = 0;
+
+	scia = nan_de_get_attr(buf, len, NAN_ATTR_SCIA, 0);
+	if (!scia)
+		return 0;
+
+	scia++;
+	scia_len = WPA_GET_LE16(scia);
+	scia += 2;
+
+	end = scia + scia_len;
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: Parsing Security Context Information attribute (len=%u)",
+		   scia_len);
+
+	/* Parse list of Security Context Identifiers */
+	while (end - scia >= (unsigned int)sizeof(struct nan_sec_ctxt)) {
+		struct nan_sec_ctxt *sec_ctx = (void *)scia;
+		u16 scid_len = le_to_host16(sec_ctx->len);
+
+		if (scid_len + (unsigned int)sizeof(*sec_ctx) > end - scia) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Invalid SCID length %u (remaining %zu)",
+				   scid_len, end - scia);
+			break;
+		}
+
+		/* Check if this is for our instance_id and is a PMKID type */
+		if (sec_ctx->scid == NAN_SEC_CTX_TYPE_ND_PMKID &&
+		    sec_ctx->instance_id == instance_id) {
+			if (scid_len == PMKID_LEN &&
+			    pmkid_count < max_pmkids) {
+				os_memcpy(&pmkid_list[pmkid_count * PMKID_LEN],
+					  sec_ctx->ctxt, PMKID_LEN);
+				pmkid_count++;
+				wpa_hexdump(MSG_DEBUG, "NAN: Parsed PMKID",
+					    sec_ctx->ctxt, PMKID_LEN);
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Unexpected SCID length %u or max PMKIDs reached",
+					   scid_len);
+			}
+		}
+
+		scia += scid_len + sizeof(*sec_ctx);
+	}
+
+	wpa_printf(MSG_DEBUG, "NAN: Parsed %zu PMKIDs from SCIA",
+		   pmkid_count);
+
+	return pmkid_count;
+}
+
+
 static void nan_de_process_elem_container(struct nan_de *de, const u8 *buf,
 					  size_t len, const u8 *peer_addr,
 					  unsigned int freq, bool p2p, bool pr)
@@ -1270,8 +1330,13 @@ static bool nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 			      u8 req_instance_id, u16 sdea_control,
 			      enum nan_service_protocol_type srv_proto_type,
 			      const u8 *ssi, size_t ssi_len,
-			      bool range_limit, int rssi)
+			      bool range_limit, int rssi,
+			      const u8 *buf, size_t buf_len)
 {
+	/* The SCIA can potentially contain a PMKID for each cipher suite */
+	u8 pmkid_list[(NAN_CS_MAX - 1) * PMKID_LEN];
+	size_t pmkid_count = 0;
+
 	if (!nan_de_filter_match(srv, matching_filter, matching_filter_len))
 		return false;
 
@@ -1311,13 +1376,22 @@ static bool nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 	}
 
 send_event:
+	/* Parse Security Context Information attribute for PMKIDs */
+	if (buf && buf_len > 0) {
+		pmkid_count = nan_de_parse_scia(buf, buf_len, instance_id,
+						pmkid_list,
+						sizeof(pmkid_list) / PMKID_LEN);
+	}
+
 	if (de->cb.discovery_result)
 		de->cb.discovery_result(
 			de->cb.ctx, srv->id, srv_proto_type,
 			ssi, ssi_len, instance_id,
 			peer_addr,
 			sdea_control & NAN_SDEA_CTRL_FSD_REQ,
-			sdea_control & NAN_SDEA_CTRL_FSD_GAS);
+			sdea_control & NAN_SDEA_CTRL_FSD_GAS,
+			pmkid_count > 0 ? pmkid_list : NULL,
+			pmkid_count);
 
 	return true;
 }
@@ -1626,7 +1700,7 @@ static bool nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
 				req_instance_id, sdea_control, srv_proto_type,
 				ssi, ssi_len,
 				ctrl & NAN_SRV_CTRL_DISCOVERY_RANGE_LIMITED,
-				rssi);
+				rssi, buf, len);
 			break;
 		case NAN_SRV_CTRL_SUBSCRIBE:
 			ret |= nan_de_rx_subscribe(
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 8af1bb2bc5..de7f08e7ea 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -37,7 +37,8 @@ struct nan_callbacks {
 				 enum nan_service_protocol_type srv_proto_type,
 				 const u8 *ssi, size_t ssi_len,
 				 int peer_publish_id,
-				 const u8 *peer_addr, bool fsd, bool fsd_gas);
+				 const u8 *peer_addr, bool fsd, bool fsd_gas,
+				 const u8 *pmkid_list, size_t pmkid_count);
 
 	void (*replied)(void *ctx, int publish_id, const u8 *peer_addr,
 			int peer_subscribe_id,
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 769208f7c5..47a33ddd1e 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -3138,7 +3138,8 @@ static void
 wpas_nan_de_discovery_result(void *ctx, int subscribe_id,
 			     enum nan_service_protocol_type srv_proto_type,
 			     const u8 *ssi, size_t ssi_len, int peer_publish_id,
-			     const u8 *peer_addr, bool fsd, bool fsd_gas)
+			     const u8 *peer_addr, bool fsd, bool fsd_gas,
+			     const u8 *pmkid_list, size_t pmkid_count)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-- 
2.53.0




More information about the Hostap mailing list