[RFC PATCH 3/6] NAN: Add support for publishing proxied services

Benjamin Berg benjamin at sipsolutions.net
Thu Feb 19 07:55:50 PST 2026


From: Benjamin Berg <benjamin.berg at intel.com>

This adds the ability to publish a proxied service by wrapping the
attributes in the appropriate Proxy Meta attribute.

Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
---
 src/common/nan_de.c             | 61 +++++++++++++++++++++++----------
 src/common/nan_de.h             |  4 +++
 wpa_supplicant/nan_supplicant.c |  4 ++-
 3 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 95d6c5621b..396b5fa5bc 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -273,6 +273,10 @@ static size_t nan_de_sdf_attrs_put(struct wpabuf *buf, struct nan_de *de,
 	u8 ctrl = type;
 	u16 sdea_ctrl = 0;
 
+	/* Proxy attribute, proxy attribute length and NMI address */
+	if (srv->publish.origin_id)
+		len += NAN_ATTR_HDR_LEN + ETH_ALEN;
+
 	/* Service Descriptor attribute */
 	sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1;
 	if (srv->matching_filter_tx && wpabuf_len(srv->matching_filter_tx)) {
@@ -296,7 +300,14 @@ static size_t nan_de_sdf_attrs_put(struct wpabuf *buf, struct nan_de *de,
 	sdea_len = 1 + 2;
 	if (ssi)
 		sdea_len += 2 + 4 + wpabuf_len(ssi);
-	len += NAN_ATTR_HDR_LEN + sdea_len;
+	if (srv->type == NAN_DE_PUBLISH) {
+		if (srv->publish.fsd)
+			sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ;
+		if (srv->publish.fsd_gas)
+			sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS;
+	}
+	if (ssi || sdea_ctrl)
+		len += NAN_ATTR_HDR_LEN + sdea_len;
 
 	/* Element Container attribute */
 	if (srv->elems)
@@ -306,11 +317,18 @@ static size_t nan_de_sdf_attrs_put(struct wpabuf *buf, struct nan_de *de,
 	if (!buf)
 		return len;
 
+	/* NAN Proxy Meta attribute */
+	if (srv->publish.origin_id) {
+		wpabuf_put_u8(buf, NAN_ATTR_PROXY_META);
+		wpabuf_put_le16(buf, len - NAN_ATTR_HDR_LEN);
+		wpabuf_put_data(buf, srv->publish.origin_nmi, ETH_ALEN);
+	}
+
 	/* Service Descriptor attribute */
 	wpabuf_put_u8(buf, NAN_ATTR_SDA);
 	wpabuf_put_le16(buf, sda_len);
 	wpabuf_put_data(buf, srv->service_id, NAN_SERVICE_ID_LEN);
-	wpabuf_put_u8(buf, srv->id); /* Instance ID */
+	wpabuf_put_u8(buf, srv->publish.origin_id ?: srv->id);
 	wpabuf_put_u8(buf, req_instance_id); /* Requestor Instance ID */
 	wpabuf_put_u8(buf, ctrl);
 
@@ -337,21 +355,17 @@ static size_t nan_de_sdf_attrs_put(struct wpabuf *buf, struct nan_de *de,
 
 	/* Service Descriptor Extension attribute */
 	if (srv->type == NAN_DE_PUBLISH || ssi) {
-		wpabuf_put_u8(buf, NAN_ATTR_SDEA);
-		wpabuf_put_le16(buf, sdea_len);
-		wpabuf_put_u8(buf, srv->id); /* Instance ID */
-		if (srv->type == NAN_DE_PUBLISH) {
-			if (srv->publish.fsd)
-				sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ;
-			if (srv->publish.fsd_gas)
-				sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS;
-		}
-		wpabuf_put_le16(buf, sdea_ctrl);
-		if (ssi) {
-			wpabuf_put_le16(buf, 4 + wpabuf_len(ssi));
-			wpabuf_put_be24(buf, OUI_WFA);
-			wpabuf_put_u8(buf, srv->srv_proto_type);
-			wpabuf_put_buf(buf, ssi);
+		if (sdea_ctrl || ssi) {
+			wpabuf_put_u8(buf, NAN_ATTR_SDEA);
+			wpabuf_put_le16(buf, sdea_len);
+			wpabuf_put_u8(buf, srv->id); /* Instance ID */
+			wpabuf_put_le16(buf, sdea_ctrl);
+			if (ssi) {
+				wpabuf_put_le16(buf, 4 + wpabuf_len(ssi));
+				wpabuf_put_be24(buf, OUI_WFA);
+				wpabuf_put_u8(buf, srv->srv_proto_type);
+				wpabuf_put_buf(buf, ssi);
+			}
 		}
 	}
 
@@ -1299,6 +1313,10 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
 	/* Follow-up function processing of a receive Follow-up message for a
 	 * Subscribe or Publish instance */
 
+	/* No processing for when it is a proxied publish for another NMI */
+	if (srv->type == NAN_DE_PUBLISH  && srv->publish.origin_id)
+		return;
+
 	if (srv->type == NAN_DE_PUBLISH &&
 	    os_reltime_initialized(&srv->pause_state_end) &&
 	    (!ether_addr_equal(peer_addr, srv->sel_peer_addr) ||
@@ -1658,7 +1676,8 @@ int nan_de_publish(struct nan_de *de, const char *service_name,
 		return -1;
 	}
 
-	if (params->proximity_ranging && params->solicited && !elems) {
+	if (params->proximity_ranging && params->solicited &&
+	    !elems && !params->origin_id) {
 		wpa_printf(MSG_INFO,
 			   "NAN: Unable to fetch proximity ranging params");
 		return -1;
@@ -2065,6 +2084,12 @@ int nan_de_transmit(struct nan_de *de, int handle,
 		return -1;
 	}
 
+	if (srv->type == NAN_DE_PUBLISH && srv->publish.origin_id) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Cannot transmit Follow-up for proxied services");
+		return -1;
+	}
+
 	if (srv->is_p2p)
 		network_id = p2p_network_id;
 	else if (srv->sync)
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index b14b22b4a0..cf9b9870e7 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -106,6 +106,10 @@ struct nan_publish_params {
 	/* Event conditions */
 	bool disable_events;
 
+	/* When acting as a proxy */
+	int origin_id;
+	u8 origin_nmi[ETH_ALEN];
+
 	/* Further Service Discovery flag */
 	bool fsd;
 
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index a42c158425..f284bc8ff8 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -777,7 +777,9 @@ int wpas_nan_publish(struct wpa_supplicant *wpa_s, const char *service_name,
 	}
 #endif /* CONFIG_NAN */
 
-	if (p2p) {
+	if (params->origin_id) {
+		/* Do not add extra elems automatically here */
+	} else if (p2p) {
 		elems = wpas_p2p_usd_elems(wpa_s, service_name);
 		addr = wpa_s->global->p2p_dev_addr;
 	} else if (params->proximity_ranging) {
-- 
2.53.0




More information about the Hostap mailing list