[PATCH 10/97] NAN: Only remove NDI station when no other NDP uses the same peer NDI

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Apr 28 13:05:11 PDT 2026


When multiple NDPs share the same peer NDI address, terminating one NDP
should not remove the NDI station if other NDPs still use it. The
nan_peer_ndi_in_use() function is used to check if any other NDP is
using the same peer NDI address before removing the station.

Add a remove_sta parameter to the ndp_disconnected callback to indicate
whether the NDI station should be removed. This is determined in nan.c
by checking if any other NDP is using the same peer NDI address.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/nan/nan.c                   | 20 ++++++++++++++++++--
 src/nan/nan.h                   |  4 +++-
 src/nan/nan_module_tests.c      |  4 +++-
 wpa_supplicant/nan_supplicant.c | 30 ++++++++++++++++++------------
 4 files changed, 42 insertions(+), 16 deletions(-)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index d8d7af8c1d..a885804e8f 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -1506,6 +1506,7 @@ static void nan_ndp_disconnected(struct nan_data *nan, struct nan_peer *peer,
 {
 	const u8 *local_ndi, *peer_ndi;
 	struct nan_ndp_id ndp_id;
+	bool remove_sta;
 
 	os_memset(&ndp_id, 0, sizeof(ndp_id));
 
@@ -1525,10 +1526,17 @@ static void nan_ndp_disconnected(struct nan_data *nan, struct nan_peer *peer,
 		peer_ndi = peer->ndp_setup.ndp->init_ndi;
 	}
 
+	/*
+	 * Remove the NDI station only if no other NDP is using the same
+	 * peer NDI address. The disconnecting NDP is in ndp_setup.ndp
+	 * (not in peer->ndps), so checking peer->ndps is sufficient.
+	 */
+	remove_sta = !nan_peer_ndi_in_use(peer, peer_ndi);
+
 	if (nan->cfg->ndp_disconnected)
 		nan->cfg->ndp_disconnected(nan->cfg->cb_ctx, &ndp_id,
 					   local_ndi, peer_ndi, reason,
-					   locally_generated);
+					   locally_generated, remove_sta);
 
 	nan_ndp_setup_stop(nan, peer);
 }
@@ -2094,9 +2102,17 @@ 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)
 {
+	/*
+	 * Remove the NDI station only if no other NDP is using the same
+	 * peer NDI address. The terminated NDP has already been removed
+	 * from peer->ndps before this function is called.
+	 */
+	bool remove_sta = !nan_peer_ndi_in_use(peer, peer_ndi);
+
 	if (nan->cfg->ndp_disconnected)
 		nan->cfg->ndp_disconnected(nan->cfg->cb_ctx, ndp_id, local_ndi,
-					   peer_ndi, reason, false);
+					   peer_ndi, reason, false,
+					   remove_sta);
 
 	/* Need to also remove the NDL if it is not needed */
 	if (dl_list_empty(&peer->ndps) && !peer->ndp_setup.ndp)
diff --git a/src/nan/nan.h b/src/nan/nan.h
index d53c7c54d7..1188ffac77 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -493,6 +493,8 @@ struct nan_config {
 	 * @reason: Disconnection reason
 	 * @locally_generated: true if the disconnection was locally generated,
 	 *     false if triggered by the peer
+	 * @remove_sta: true if the NDI station should be removed (no other NDPs
+	 *     using the same peer NDI)
 	 *
 	 * This callback notifies that an NDP has been disconnected. It can be
 	 * called both during NDP establishment (indicating failure) or after
@@ -501,7 +503,7 @@ struct nan_config {
 	void (*ndp_disconnected)(void *ctx, struct nan_ndp_id *ndp_id,
 				 const u8 *local_ndi, const u8 *peer_ndi,
 				 enum nan_reason reason,
-				 bool locally_generated);
+				 bool locally_generated, bool remove_sta);
 
 	/**
 	 * get_chans - Get the prioritized allowed channel information to be
diff --git a/src/nan/nan_module_tests.c b/src/nan/nan_module_tests.c
index 30d559642b..9f376278d1 100644
--- a/src/nan/nan_module_tests.c
+++ b/src/nan/nan_module_tests.c
@@ -640,6 +640,7 @@ static int nan_test_ndp_connected_cb(void *ctx,
  * @peer_ndi: Peer NDI address
  * @reason: Reason for disconnection
  * @locally_generated: true if locally generated, false if triggered by peer
+ * @remove_sta: true if the NDI station should be removed
  *
  * The handling of the event is done asynchronously through the NAN test actions
  * processing.
@@ -648,7 +649,8 @@ static void nan_test_ndp_disconnected_cb(void *ctx, struct nan_ndp_id *ndp_id,
 					 const u8 *local_ndi,
 					 const u8 *peer_ndi,
 					 enum nan_reason reason,
-					 bool locally_generated)
+					 bool locally_generated,
+					 bool remove_sta)
 {
 	struct nan_device *dev = ctx;
 
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 70470a8c9e..e8c5b25c4c 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -571,7 +571,8 @@ remove_sta:
 
 static void wpas_nan_remove_ndi_sta(struct wpa_supplicant *wpa_s,
 				    const u8 *local_ndi,
-				    const u8 *peer_ndi)
+				    const u8 *peer_ndi,
+				    bool remove_sta)
 {
 	struct wpa_supplicant *ndi_wpa_s;
 
@@ -583,14 +584,6 @@ static void wpas_nan_remove_ndi_sta(struct wpa_supplicant *wpa_s,
 		return;
 	}
 
-	if (wpa_drv_sta_set_flags(ndi_wpa_s, peer_ndi, WPA_STA_AUTHORIZED,
-				  0, ~WPA_STA_AUTHORIZED))
-		wpa_printf(MSG_DEBUG,
-			   "NAN: Failed to clear authorized flag for NDI station");
-
-	wpas_nan_remove_ndi_keys(ndi_wpa_s, peer_ndi);
-	wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
-
 	if (!ndi_wpa_s->nan_ndi_ndp_refcount)
 		return;
 
@@ -599,8 +592,20 @@ static void wpas_nan_remove_ndi_sta(struct wpa_supplicant *wpa_s,
 		   MACSTR ")", ndi_wpa_s->nan_ndi_ndp_refcount,
 		   MAC2STR(peer_ndi));
 
-	/* Set operstate DORMANT only when the last NDP is removed from this NDI
+	/* Only remove the NDI station if no other NDP is using the same
+	 * peer NDI address
 	 */
+	if (remove_sta) {
+		if (wpa_drv_sta_set_flags(ndi_wpa_s, peer_ndi, WPA_STA_AUTHORIZED,
+					  0, ~WPA_STA_AUTHORIZED))
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Failed to clear authorized flag for NDI station");
+
+		wpas_nan_remove_ndi_keys(ndi_wpa_s, peer_ndi);
+		wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
+	}
+
+	/* Set operstate DORMANT only when last NDP is removed from this NDI */
 	if (!ndi_wpa_s->nan_ndi_ndp_refcount)
 		wpa_drv_set_operstate(ndi_wpa_s, 0);
 }
@@ -633,11 +638,12 @@ static void wpas_nan_ndp_disconnected_cb(void *ctx, struct nan_ndp_id *ndp_id,
 					 const u8 *local_ndi,
 					 const u8 *peer_ndi,
 					 enum nan_reason reason,
-					 bool locally_generated)
+					 bool locally_generated,
+					 bool remove_sta)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	wpas_nan_remove_ndi_sta(wpa_s, local_ndi, peer_ndi);
+	wpas_nan_remove_ndi_sta(wpa_s, local_ndi, peer_ndi, remove_sta);
 	wpas_notify_nan_ndp_disconnected(wpa_s, ndp_id->peer_nmi,
 					 ndp_id->id, local_ndi, peer_ndi,
 					 reason, locally_generated);
-- 
2.53.0




More information about the Hostap mailing list