[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, ¶ms)) {
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