[PATCH 59/97] NAN: Add handling of max idle period

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Apr 28 13:06:00 PDT 2026


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

Track the inactivity of NAN peers:

- For each peer, iterate overall NDPs and get the
  inactivity time for the interface and peer NDI
  associated with the NDP.
- If for a given peer, the inactivity period on
  all the NDPs is greater than the local max idle period,
  disconnect all the NDPs for the peer.

In addition, add support to configuring the local max NDL
idle time.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/nan/nan.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/nan/nan.h |  12 +++++
 2 files changed, 153 insertions(+)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index 53b82492f7..0e09dd6f67 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -21,6 +21,7 @@
 #define NAN_NDP_SETUP_TIMEOUT_SHORT 2
 
 static void nan_peer_state_timeout(void *eloop_ctx, void *timeout_ctx);
+static void nan_idle_period_timeout(void *eloop_ctx, void *timeout_ctx);
 static void nan_ndp_disconnected(struct nan_data *nan, struct nan_peer *peer,
 				 enum nan_reason reason,
 				 bool locally_generated);
@@ -382,6 +383,8 @@ void nan_stop(struct nan_data *nan)
 		return;
 	}
 
+	eloop_cancel_timeout(nan_idle_period_timeout, nan, NULL);
+
 	if (nan->igtk.igtk_len) {
 		if (nan->cfg->set_group_key(nan->cfg->cb_ctx, WPA_ALG_NONE,
 					    NULL, nan->igtk_id, NULL, NULL,
@@ -1668,6 +1671,101 @@ static void nan_terminate_ndps_for_ndi(struct nan_data *nan,
 }
 
 
+static void nan_handle_idle_period(struct nan_data *nan)
+{
+	struct nan_peer *peer;
+	int next_timeout = 0;
+
+	eloop_cancel_timeout(nan_idle_period_timeout, nan, NULL);
+
+	if (!nan->cfg->get_peer_inactivity || !nan->cfg->max_ndl_idle_period)
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: Handle idle period timeout: max_idle_period=%d sec",
+		   nan->cfg->max_ndl_idle_period);
+
+	dl_list_for_each(peer, &nan->peer_list, struct nan_peer, list) {
+		int peer_inactive = -1;
+		struct nan_ndp *pndp;
+
+		if (dl_list_empty(&peer->ndps) || !peer->ndl)
+			continue;
+
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Check idle period for peer=" MACSTR,
+			   MAC2STR(peer->nmi_addr));
+
+		/* Find the minimal inactive time over all NDPs */
+		dl_list_for_each(pndp, &peer->ndps, struct nan_ndp, list) {
+			const u8 *local_ndi, *peer_ndi;
+			int inactive;
+
+			if (pndp->initiator) {
+				local_ndi = pndp->init_ndi;
+				peer_ndi = pndp->resp_ndi;
+			} else {
+				local_ndi = pndp->resp_ndi;
+				peer_ndi = pndp->init_ndi;
+			}
+
+			inactive =
+				nan->cfg->get_peer_inactivity(nan->cfg->cb_ctx,
+							      local_ndi,
+							      peer_ndi);
+			wpa_printf(MSG_DEBUG,
+				   "NAN: local=" MACSTR ", peer" MACSTR " : inactivity=%d sec",
+				   MAC2STR(local_ndi), MAC2STR(peer_ndi),
+				   inactive);
+
+			if (inactive < 0)
+				continue;
+
+			/*
+			 * peer_inactive would eventually hold the minimal
+			 * inactive time over all <local NDI, peer NDI> couples
+			 */
+			if (peer_inactive == -1 || inactive < peer_inactive)
+				peer_inactive = inactive;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Peer " MACSTR " has been inactive for %d seconds",
+			   MAC2STR(peer->nmi_addr), peer_inactive);
+
+		if (peer_inactive >= nan->cfg->max_ndl_idle_period) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Peer " MACSTR
+				   " has been inactive for too long, removing NDPs",
+				   MAC2STR(peer->nmi_addr));
+			nan_peer_del_all_ndps(nan, peer->nmi_addr);
+			continue;
+		} else if (peer_inactive == -1) {
+			peer_inactive = 0;
+		}
+
+		if (!next_timeout ||
+		    next_timeout >
+		    nan->cfg->max_ndl_idle_period - peer_inactive)
+			next_timeout =
+				nan->cfg->max_ndl_idle_period - peer_inactive;
+	}
+
+	wpa_printf(MSG_DEBUG, "NAN: Next idle period timeout in %d seconds",
+		   next_timeout);
+
+	if (next_timeout)
+		eloop_register_timeout(next_timeout, 0,
+				       nan_idle_period_timeout, nan, NULL);
+}
+
+
+static void nan_idle_period_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	nan_handle_idle_period(eloop_ctx);
+}
+
+
 static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
 {
 	struct nan_ndp_connection_params params;
@@ -1734,6 +1832,7 @@ static int nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
 	peer->ndp_setup.ndp = NULL;
 
 	nan_ndp_setup_stop(nan, peer);
+	nan_handle_idle_period(nan);
 
 	return 0;
 }
@@ -3120,6 +3219,48 @@ int nan_set_beacon_prot(struct nan_data *nan, bool enable)
 
 	nan->cfg->security_capab &= ~NAN_CS_INFO_CAPA_GTK_SUPP_MASK;
 	nan->cfg->security_capab |= gtk_supp << NAN_CS_INFO_CAPA_GTK_SUPP_POS;
+	return 0;
+}
+
 
+/**
+ * nan_set_max_ndl_idle_period - Set maximum NDL idle period
+ *
+ * @nan: Pointer to NAN data structure
+ * @max_idle_period: Maximum idle period in seconds
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int nan_set_max_ndl_idle_period(struct nan_data *nan, u16 max_idle_period)
+{
+	if (!nan)
+		return -1;
+
+	if (!nan->cfg->get_peer_inactivity) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Cannot set max NDL idle period as get_peer_inactivity callback is not set");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: Setting max NDL idle period to %u (prev=%u) seconds",
+		   max_idle_period, nan->cfg->max_ndl_idle_period);
+
+	nan->cfg->max_ndl_idle_period = max_idle_period;
+
+	if (!nan->nan_started)
+		return 0;
+
+	/*
+	 * Handle the current timeout. If a positive idle period is set
+	 * configure the timeout logic to run in 1 second (as calling it
+	 * immediately could cause NDP termination in the same context, and
+	 * the caller might be able to handle it).
+	 */
+	eloop_cancel_timeout(nan_idle_period_timeout, nan, NULL);
+	if (max_idle_period)
+		eloop_register_timeout(1, 0,
+				       nan_idle_period_timeout,
+				       nan, NULL);
 	return 0;
 }
diff --git a/src/nan/nan.h b/src/nan/nan.h
index 6e01fb4938..b0f0fd0bac 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -770,6 +770,17 @@ struct nan_config {
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*get_seqnum)(void *ctx, int key_idx, u8 *seq, u8 *ndi_addr);
+
+	/**
+	 * get_peer_inactivity - Get the inactivity time for a peer
+	 *
+	 * @ctx: Callback context from cb_ctx
+	 * @local_ndi: Local NDI address
+	 * @peer_ndi: Peer NDI address
+	 * Returns: Peer inactivity in seconds, negative value on failure
+	 */
+	int (*get_peer_inactivity)(void *ctx, const u8 *local_ndi,
+				   const u8 *peer_ndi);
 };
 
 struct nan_data * nan_init(const struct nan_config *cfg);
@@ -851,6 +862,7 @@ struct wpabuf * nan_crypto_derive_nira_tag(const u8 *nik, size_t nik_len,
 int nan_ndp_requested_gtk_csid(struct nan_data *nan, struct nan_ndp_id *ndp_id);
 int nan_set_mgmt_group_cipher(struct nan_data *nan, int cipher);
 int nan_set_beacon_prot(struct nan_data *nan, bool enable);
+int nan_set_max_ndl_idle_period(struct nan_data *nan, u16 max_idle_period);
 #ifdef CONFIG_PASN
 int nan_pairing_add_attrs(struct nan_data *nan_data, struct wpabuf *buf);
 int nan_pairing_initiate_pasn_auth(struct nan_data *nan_data, const u8 *addr,
-- 
2.53.0




More information about the Hostap mailing list