[RFC v2 68/99] wpa_supplicant: Add support for NDP_RESPONSE command

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Dec 23 03:52:12 PST 2025


This allows to accept or reject NDP request.
Upper layer is expected to create the corresponding NAN data interface
and configure a compliant NAN schedule prior to accepting an NDP request
received via NAN-NDP-REQUEST event.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 wpa_supplicant/ctrl_iface.c     |   3 +
 wpa_supplicant/nan_supplicant.c | 168 ++++++++++++++++++++++++++++++++
 wpa_supplicant/nan_supplicant.h |   1 +
 3 files changed, 172 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 3a8b3298cc..05debdb418 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -14353,6 +14353,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strncmp(buf, "NAN_NDP_REQUEST ", 16) == 0) {
 		if (wpas_nan_ndp_request(wpa_s, buf + 16) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "NAN_NDP_RESPONSE ", 17) == 0) {
+		if (wpas_nan_ndp_response(wpa_s, buf + 17) < 0)
+			reply_len = -1;
 #endif /* CONFIG_NAN */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index b231628b5f..11f8844bac 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -1406,6 +1406,174 @@ fail:
 }
 
 
+/* Command format NAN_NDP_RESPONSE accept|reject peer_nmi=<nmi>
+   [reason_code=<reject_reason>]
+   [ndi=<ifname> handle=<service_handle> init_ndi=<ndi>
+   ndp_id=<id> [ssi=<hexdata>] [qos=<slots:latency>]] */
+int wpas_nan_ndp_response(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	struct nan_ndp_params ndp;
+	struct wpabuf *ssi_buf = NULL;
+	char *token, *context = NULL;
+	char *pos;
+	int ret = -1;
+
+	os_memset(&ndp, 0, sizeof(ndp));
+
+	if (!wpas_nan_ready(wpa_s))
+		return -1;
+
+	ndp.type = NAN_NDP_ACTION_RESP;
+	ndp.qos.min_slots = NAN_QOS_MIN_SLOTS_NO_PREF;
+	ndp.qos.max_latency = NAN_QOS_MAX_LATENCY_NO_PREF;
+
+	/* Parse accept/reject status - first parameter is mandatory */
+	token = str_token(cmd, " ", &context);
+	if (!token) {
+		wpa_printf(MSG_DEBUG, "NAN: Missing accept/reject parameter");
+		return -1;
+	}
+
+	if (os_strcmp(token, "accept") == 0) {
+		ndp.u.resp.status = NAN_NDP_STATUS_ACCEPTED;
+	} else if (os_strcmp(token, "reject") == 0) {
+		ndp.u.resp.status = NAN_NDP_STATUS_REJECTED;
+	} else {
+		wpa_printf(MSG_DEBUG, "NAN: Invalid accept/reject parameter: %s", token);
+		return -1;
+	}
+
+	/* Parse optional parameters */
+	while ((token = str_token(cmd, " ", &context))) {
+		pos = os_strchr(token, '=');
+		if (!pos) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Invalid parameter format: %s",
+				   token);
+			goto fail;
+		}
+		*pos++ = '\0';
+
+		if (os_strcmp(token, "reason_code") == 0) {
+			ndp.u.resp.reason_code = atoi(pos);
+		} else if (os_strcmp(token, "ndi") == 0) {
+			struct wpa_supplicant *ndi_wpa_s;
+
+			ndi_wpa_s = wpa_supplicant_get_iface(wpa_s->global, pos);
+			if (!ndi_wpa_s) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: NDI interface not found: %s",
+					   pos);
+				goto fail;
+			}
+
+			if (!ndi_wpa_s->nan_data) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Interface %s is not a NAN data interface",
+					   pos);
+				goto fail;
+			}
+
+			os_memcpy(ndp.u.resp.resp_ndi, ndi_wpa_s->own_addr,
+				  ETH_ALEN);
+
+		} else if (os_strcmp(token, "peer_nmi") == 0) {
+			if (hwaddr_aton(pos, ndp.ndp_id.peer_nmi) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Invalid peer NMI address: %s",
+					   pos);
+				goto fail;
+			}
+		} else if (os_strcmp(token, "ndp_id") == 0) {
+			ndp.ndp_id.id = atoi(pos);
+
+		} else if (os_strcmp(token, "init_ndi") == 0) {
+			if (hwaddr_aton(pos, ndp.ndp_id.init_ndi) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Invalid initiator NDI address: %s",
+					   pos);
+				goto fail;
+			}
+
+		} else if (os_strcmp(token, "ssi") == 0) {
+			ssi_buf = wpabuf_parse_bin(pos);
+			if (!ssi_buf) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Invalid SSI data: %s", pos);
+				goto fail;
+			}
+
+			ndp.ssi_len = wpabuf_len(ssi_buf);
+			ndp.ssi = wpabuf_head(ssi_buf);
+		} else if (os_strcmp(token, "qos") == 0) {
+			if (sscanf(pos, "%hhu:%hu",
+				   &ndp.qos.min_slots,
+				   &ndp.qos.max_latency) != 2) {
+				wpa_printf(MSG_DEBUG,
+					   "NAN: Invalid QoS parameter: %s",
+					   pos);
+				goto fail;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "NAN: Unknown parameter: %s",
+				   token);
+		}
+	}
+
+	/* Validate required parameters for accept case */
+	if (ndp.u.resp.status == NAN_NDP_STATUS_ACCEPTED) {
+		if (is_zero_ether_addr(ndp.u.resp.resp_ndi)) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Missing required parameter for accept: ndi");
+			goto fail;
+		}
+	}
+
+	/* Validate common required parameters */
+	if (is_zero_ether_addr(ndp.ndp_id.peer_nmi)) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Missing required parameter: peer_nmi");
+		goto fail;
+	}
+
+	if (is_zero_ether_addr(ndp.ndp_id.init_ndi)) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Missing required parameter: init_ndi");
+		goto fail;
+	}
+
+	if (!ndp.ndp_id.id) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Missing required parameter: ndp_id");
+		goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "NAN: %s NDP response for peer " MACSTR
+		   " ndp_id=%u",
+		   ndp.u.resp.status == NAN_NDP_STATUS_ACCEPTED ? "Accepting" : "Rejecting",
+		   MAC2STR(ndp.ndp_id.peer_nmi), ndp.ndp_id.id);
+
+	if (wpas_nan_set_ndp_schedule(wpa_s, &ndp) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Failed to set NDP schedule");
+		goto fail;
+	}
+
+	/* If we initiated the NDP setup, this must be the confirmation */
+	if (ether_addr_equal(ndp.u.resp.resp_ndi, ndp.ndp_id.init_ndi))
+		ndp.type = NAN_NDP_ACTION_CONF;
+
+	ret = nan_handle_ndp_setup(wpa_s->nan, &ndp);
+	if (ret < 0)
+		wpa_printf(MSG_DEBUG, "NAN: Failed to handle NDP response");
+
+fail:
+	wpabuf_free(ndp.sched.elems);
+	wpabuf_free(ssi_buf);
+	return ret;
+}
+
+
 void wpas_nan_cluster_join(struct wpa_supplicant *wpa_s,
 			   const u8 *cluster_id,
 			   bool new_cluster)
diff --git a/wpa_supplicant/nan_supplicant.h b/wpa_supplicant/nan_supplicant.h
index d7c0cc2800..61a0a5c4d5 100644
--- a/wpa_supplicant/nan_supplicant.h
+++ b/wpa_supplicant/nan_supplicant.h
@@ -28,6 +28,7 @@ int wpas_nan_sched_config_map(struct wpa_supplicant *wpa_s, const char *cmd);
 int wpas_nan_ndp_request(struct wpa_supplicant *wpa_s, char *cmd);
 void wpas_nan_rx_naf(struct wpa_supplicant *wpa_s,
 		     const struct ieee80211_mgmt *mgmt, size_t len);
+int wpas_nan_ndp_response(struct wpa_supplicant *wpa_s, char *cmd);
 
 #else /* CONFIG_NAN */
 
-- 
2.49.0




More information about the Hostap mailing list