[RFC v2 34/99] NAN: Support handling NDP termination from peer in NDP SM

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Dec 23 03:51:38 PST 2025


From: Ilan Peer <ilan.peer at intel.com>

Add support for terminating an NDP whose setup
is complete. In case there are no more NDPs with the
peer, the NDL is also torn down.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/nan/nan.c     | 18 +++++++++-
 src/nan/nan_i.h   |  3 ++
 src/nan/nan_ndp.c | 90 ++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 89 insertions(+), 22 deletions(-)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index f619647ba1..8869bd8b29 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -1250,8 +1250,11 @@ static int nan_action_rx_ndp(struct nan_data *nan, struct nan_peer *peer,
 	int ret;
 
 	ret = nan_ndp_handle_ndp_attr(nan, peer, msg);
-	if (ret)
+	if (ret) {
+		if (ret > 0)
+			ret = 0;
 		return ret;
+	}
 
 	/*
 	 * NDP request: Also process the NDL/NDC/QoS attributes and store the
@@ -1615,3 +1618,16 @@ int nan_handle_ndp_setup(struct nan_data *nan, struct nan_ndp_params *params)
 	nan_set_peer_timeout(nan, peer, timeout, 0);
 	return ret;
 }
+
+
+void nan_ndp_terminated(struct nan_data *nan, struct nan_peer *peer,
+			struct nan_ndp_id *ndp_id, const u8 *local_ndi,
+			const u8 *peer_ndi, enum nan_reason reason)
+{
+	nan->cfg->ndp_disconnected(nan->cfg->cb_ctx, ndp_id, local_ndi, peer_ndi,
+				   reason);
+
+	/* Need to also remove the NDL if it is not needed */
+	if (dl_list_empty(&peer->ndps) && !peer->ndp_setup.ndp)
+		nan_ndl_reset(nan, peer);
+}
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index baccfa6467..632e68b765 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -463,4 +463,7 @@ nan_sched_bf_covered_by_avail_entries_and_chan(struct nan_data *nan,
 struct bitfield * nan_avail_entries_to_bf(struct nan_data *nan,
 					  const struct dl_list *avail_entries,
 					  u8 op_class, u16 cbm, u16 pri_cbm);
+void nan_ndp_terminated(struct nan_data *nan, struct nan_peer *peer,
+			struct nan_ndp_id *ndp_id, const u8 *local_ndi,
+			const u8 *peer_ndi, enum nan_reason reason);
 #endif
diff --git a/src/nan/nan_ndp.c b/src/nan/nan_ndp.c
index c18e9e8ef5..51a2b60854 100644
--- a/src/nan/nan_ndp.c
+++ b/src/nan/nan_ndp.c
@@ -473,33 +473,79 @@ static int nan_ndp_attr_handle_term(struct nan_data *nan, struct nan_peer *peer,
 				    struct ieee80211_ndp *ndp_attr, u8 status)
 {
 	struct nan_ndp_setup *ndp_setup = &peer->ndp_setup;
+	struct nan_ndp_id ndp_id;
+	const u8 *local_ndi, *peer_ndi;
+	struct nan_ndp *pndp;
+	bool found;
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: NDP: Termination peer=" MACSTR " ndp_id=%u, init_ndi=" MACSTR,
+		   MAC2STR(peer->nmi_addr), ndp_attr->ndp_id,
+		   MAC2STR(ndp_attr->initiator_ndi));
 
 	/*
-	 * This should not really happen, but just in case,
-	 * terminate the establishment.
+	 * This should not really happen, but just in case, terminate the
+	 * establishment. Since the NDP establishment is not yet done, the NDP
+	 * is not added to the list of NDPs, so just reject the establishment.
 	 */
-	if (ndp_setup->ndp) {
-		if (ndp_setup->ndp->ndp_id == ndp_attr->ndp_id &&
-		    os_memcmp(ndp_setup->ndp->init_ndi,
-			      ndp_attr->initiator_ndi,
-			      ETH_ALEN) == 0) {
-			wpa_printf(MSG_DEBUG,
-				   "NAN: NDP: term: WIP with peer. Terminate");
+	if (ndp_setup->ndp && ndp_setup->ndp->ndp_id == ndp_attr->ndp_id &&
+	    os_memcmp(ndp_setup->ndp->init_ndi, ndp_attr->initiator_ndi,
+		      ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: NDP: Termination while NDP is in progress");
 
-			nan_ndp_set_state(nan, &peer->ndp_setup,
-					  NAN_NDP_STATE_DONE);
-			ndp_setup->status = NAN_NDP_STATUS_REJECTED;
-			ndp_setup->reason = NAN_REASON_UNSPECIFIED_REASON;
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "NAN: NDP: term: different NDP WIP with peer. Ignore");
-		}
+		nan_ndp_set_state(nan, &peer->ndp_setup, NAN_NDP_STATE_DONE);
+		ndp_setup->status = NAN_NDP_STATUS_REJECTED;
+		ndp_setup->reason = NAN_REASON_UNSPECIFIED_REASON;
 		return 0;
 	}
 
-	/* TODO: handle already established NDPs */
-	wpa_printf(MSG_DEBUG, "NAN: NDP: Terminate established NDP");
-	return 0;
+	/* Find the NDP in the list of active NDPs */
+	found = false;
+	dl_list_for_each(pndp, &peer->ndps, struct nan_ndp, list) {
+		if (pndp->ndp_id == ndp_attr->ndp_id &&
+		    os_memcmp(pndp->init_ndi, ndp_attr->initiator_ndi,
+			      ETH_ALEN) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		wpa_printf(MSG_DEBUG, "NAN: NDP: termination but NDP does not exist");
+		return 1;
+	}
+
+	wpa_printf(MSG_DEBUG, "NAN: NDP: Terminating");
+
+	os_memcpy(ndp_id.peer_nmi, peer->nmi_addr, ETH_ALEN);
+	os_memcpy(ndp_id.init_ndi, pndp->init_ndi, ETH_ALEN);
+	ndp_id.id = pndp->ndp_id;
+
+	if (pndp->initiator) {
+		local_ndi = pndp->init_ndi;
+		peer_ndi = pndp->resp_ndi;
+	} else {
+		local_ndi = pndp->resp_ndi;
+		peer_ndi = pndp->init_ndi;
+	}
+
+	/*
+	 * Remove the NDP from the list of active NDPs before calling
+	 * nan_ndp_terminated() as the functions checks the list of NDPs to
+	 * determine if the NDL should be reset as well.
+	 * Free the NDP only after the call as the NDI addresses are still
+	 * referenced.
+	 */
+	dl_list_del(&pndp->list);
+
+	nan_ndp_terminated(nan, peer, &ndp_id, local_ndi, peer_ndi,
+			   ndp_attr->reason_code);
+
+	os_free(pndp);
+
+	/* Indicate that no further processing is needed */
+	return 1;
 }
 
 
@@ -509,7 +555,9 @@ static int nan_ndp_attr_handle_term(struct nan_data *nan, struct nan_peer *peer,
  * @nan: NAN module context from nan_init()
  * @peer: The peer from which the original message was received
  * @msg: Parsed nan action frame
- * Returns: 0 on success, negative on failure
+ * Returns: 0 on success processing indicating that processing can continue; 1
+ * in case of successful processing but no further processing is needed;
+ * negative on failure.
  */
 int nan_ndp_handle_ndp_attr(struct nan_data *nan, struct nan_peer *peer,
 			    struct nan_msg *msg)
-- 
2.49.0




More information about the Hostap mailing list