[PATCH 09/97] NAN: Skip duplicate NDI station add for second NDP with same peer

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


When establishing a second NDP with the same peer using the same NDI,
the peer's NDI station already exists in the kernel. Attempting to add
it again fails with -ENOTUNIQ on drivers that set NEEDS_UNIQUE_STA_ADDR
and with -EEXIST otherwise. EEXIST error value was ignored by
driver_nl80211.c, however -ENOTUNIQ resulted in a failure.

To fix it, add nan_peer_ndi_in_use() helper to check if the peer NDI is
already used by another NDP. Set the new_ndi_sta flag in
nan_ndp_connection_params to indicate whether a new station needs to
be added.

In wpas_nan_add_ndi_sta(), skip wpa_drv_sta_add() when new_ndi_sta is
false. For security upgrade cases (existing station but new keys),
set MFP flag via wpa_drv_sta_set_flags().

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/nan/nan.c                   | 19 +++++++++
 src/nan/nan.h                   |  3 ++
 wpa_supplicant/nan_supplicant.c | 68 ++++++++++++++++++++++-----------
 3 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index 52db635a96..d8d7af8c1d 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -1437,6 +1437,24 @@ static void nan_ndp_action_notif(struct nan_data *nan, struct nan_peer *peer)
 }
 
 
+static bool nan_peer_ndi_in_use(struct nan_peer *peer, const u8 *peer_ndi)
+{
+	struct nan_ndp *ndp;
+
+	dl_list_for_each(ndp, &peer->ndps, struct nan_ndp, list) {
+		if (ndp->initiator) {
+			if (ether_addr_equal(ndp->resp_ndi, peer_ndi))
+				return true;
+		} else {
+			if (ether_addr_equal(ndp->init_ndi, peer_ndi))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+
 static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
 {
 	struct nan_ndp_connection_params params;
@@ -1465,6 +1483,7 @@ static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
 						     params.peer_ndi,
 						     params.local_ndi);
 	params.first_ndp = dl_list_empty(&peer->ndps);
+	params.new_ndi_sta = !nan_peer_ndi_in_use(peer, params.peer_ndi);
 	if (nan->cfg->ndp_connected &&
 	    nan->cfg->ndp_connected(nan->cfg->cb_ctx, &params)) {
 		wpa_printf(MSG_DEBUG, "NAN: NDP connected notification failed");
diff --git a/src/nan/nan.h b/src/nan/nan.h
index 983e81b56c..d53c7c54d7 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -287,6 +287,8 @@ struct nan_channels {
  * @ssi_len: Service specific information length
  * @install_keys: Whether the new keys should be installed
  * @first_ndp: Whether this is the first NDP with the peer
+ * @new_ndi_sta: Whether a new NDI station needs to be added (peer_ndi not
+ * 	already used by another NDP with this peer)
  */
 struct nan_ndp_connection_params {
 	struct nan_ndp_id ndp_id;
@@ -296,6 +298,7 @@ struct nan_ndp_connection_params {
 	size_t ssi_len;
 	bool install_keys;
 	bool first_ndp;
+	bool new_ndi_sta;
 };
 
 /**
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 93c65694bf..70470a8c9e 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -452,7 +452,7 @@ static int wpas_nan_configure_nmi_sta_capa(struct wpa_supplicant *wpa_s,
 static int wpas_nan_add_ndi_sta(struct wpa_supplicant *wpa_s,
 				const u8 *peer_nmi, const u8 *local_ndi,
 				const u8 *peer_ndi, bool install_keys,
-				bool first_ndp)
+				bool first_ndp, bool new_ndi_sta)
 {
 	u8 tk[WPA_TK_MAX_LEN];
 	size_t tk_len;
@@ -479,45 +479,63 @@ static int wpas_nan_add_ndi_sta(struct wpa_supplicant *wpa_s,
 		return -1;
 	}
 
-	os_memset(&sta_params, 0, sizeof(sta_params));
-	sta_params.addr = peer_ndi;
-	sta_params.nmi_addr = peer_nmi;
-	sta_params.flags = WPA_STA_AUTHENTICATED | WPA_STA_ASSOCIATED;
+	if (new_ndi_sta) {
+		os_memset(&sta_params, 0, sizeof(sta_params));
+		sta_params.addr = peer_ndi;
+		sta_params.nmi_addr = peer_nmi;
+		sta_params.flags = WPA_STA_AUTHENTICATED | WPA_STA_ASSOCIATED;
 
-	/* Set MFP flag early, to prevent races until keys are installed */
-	if (install_keys)
-		sta_params.flags |= WPA_STA_MFP;
-	else
-		sta_params.flags |= WPA_STA_AUTHORIZED;
+		/* Set MFP flag early, to prevent races until keys are installed */
+		if (install_keys)
+			sta_params.flags |= WPA_STA_MFP;
+		else
+			sta_params.flags |= WPA_STA_AUTHORIZED;
 
-	if (wpa_drv_sta_add(ndi_wpa_s, &sta_params)) {
+		if (wpa_drv_sta_add(ndi_wpa_s, &sta_params)) {
+			wpa_printf(MSG_INFO,
+				   "NAN: Failed to add NDI station for peer " MACSTR,
+				   MAC2STR(peer_ndi));
+			return -1;
+		}
+	} else {
 		wpa_printf(MSG_INFO,
-			   "NAN: Failed to add NDI station for peer " MACSTR,
+			   "NAN: NDI station already exists for peer " MACSTR,
 			   MAC2STR(peer_ndi));
-		return -1;
+		/* Set MFP flag if keys will be installed (security upgrade) */
+		if (install_keys &&
+		    wpa_drv_sta_set_flags(ndi_wpa_s, peer_ndi, WPA_STA_MFP,
+					  WPA_STA_MFP, ~0)) {
+			wpa_printf(MSG_INFO,
+				   "NAN: Failed to set MFP flag for peer " MACSTR,
+				   MAC2STR(peer_ndi));
+			return -1;
+		}
 	}
 
 	if (!install_keys) {
-		wpa_printf(MSG_DEBUG,
-			   "NAN: NDI station added without keys for peer "
-			   MACSTR, MAC2STR(peer_ndi));
+		if (new_ndi_sta)
+			wpa_printf(MSG_DEBUG,
+				   "NAN: NDI station added without keys for peer "
+				   MACSTR, MAC2STR(peer_ndi));
+		else
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Using existing NDI station without new keys for peer "
+				   MACSTR, MAC2STR(peer_ndi));
 		goto out_success;
 	}
 
 	if (nan_peer_get_tk(wpa_s->nan, peer_nmi, peer_ndi, local_ndi, tk,
 			    &tk_len, &csid)) {
 		wpa_printf(MSG_INFO, "NAN: Failed to get TK for NDI station");
-		wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
-		return -1;
+		goto remove_sta;
 	}
 
 	if (wpas_nan_set_ndi_keys(ndi_wpa_s, peer_ndi, csid, tk, tk_len)) {
 		wpa_printf(MSG_INFO,
 			   "NAN: Failed to set NDI keys for peer " MACSTR,
 			   MAC2STR(peer_ndi));
-		wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
 		forced_memzero(tk, tk_len);
-		return -1;
+		goto remove_sta;
 	}
 	forced_memzero(tk, tk_len);
 
@@ -526,8 +544,7 @@ static int wpas_nan_add_ndi_sta(struct wpa_supplicant *wpa_s,
 		wpa_printf(MSG_INFO,
 			   "NAN: Failed to set authorize for NDI station");
 		wpas_nan_remove_ndi_keys(ndi_wpa_s, peer_ndi);
-		wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
-		return -1;
+		goto remove_sta;
 	}
 
 out_success:
@@ -544,6 +561,11 @@ out_success:
 		wpa_drv_set_operstate(ndi_wpa_s, 1);
 
 	return 0;
+
+remove_sta:
+	if (new_ndi_sta)
+		wpa_drv_sta_remove(ndi_wpa_s, peer_ndi);
+	return -1;
 }
 
 
@@ -592,7 +614,7 @@ static int wpas_nan_ndp_connected_cb(void *ctx,
 	if (wpas_nan_add_ndi_sta(wpa_s, params->ndp_id.peer_nmi,
 				 params->local_ndi, params->peer_ndi,
 				 params->install_keys,
-				 params->first_ndp) < 0) {
+				 params->first_ndp, params->new_ndi_sta) < 0) {
 		wpa_printf(MSG_INFO,
 			   "NAN: Failed to add NDI station for NDP connection");
 		return -1;
-- 
2.53.0




More information about the Hostap mailing list