[RFC v2 55/99] NAN: Add NAN module testing for secure state machine

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


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

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/nan/nan_module_test_cases.c | 153 ++++++++++++++++++++++++++++++++
 src/nan/nan_module_tests.c      |  52 +++++++++++
 src/nan/nan_module_tests.h      |  16 ++++
 3 files changed, 221 insertions(+)

diff --git a/src/nan/nan_module_test_cases.c b/src/nan/nan_module_test_cases.c
index 43e08d34b4..8a38f2f747 100644
--- a/src/nan/nan_module_test_cases.c
+++ b/src/nan/nan_module_test_cases.c
@@ -375,6 +375,156 @@ static struct nan_test_case three_way_ndp_two_way_ndl_reject = {
 };
 
 
+static struct nan_test_case four_way_ndp_two_way_ndl_chan_149_ccm_128 = {
+	.name = "Four way NDP and two way NDL channel 149 with CCMP 128",
+	.pub_conf = {
+		.schedule_cb = nan_test_schedule_cb_all_ndc,
+		.get_chans_cb = nan_test_get_chans_default,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_CONNECTED,
+				.csid = NAN_CS_SK_CCM_128,
+				.expected_csid = NAN_CS_SK_CCM_128,
+			},
+		},
+		.pot_avail = {
+			0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,
+			0xba, 0x02, 0x20, 0x02, 0x04
+		},
+		.pot_avail_len = 13,
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+		},
+	},
+	.sub_conf  = {
+		.schedule_cb = nan_test_schedule_cb_all_no_ndc,
+		.get_chans_cb = nan_test_get_chans_default,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_CONNECTED,
+				.csid = NAN_CS_SK_CCM_128,
+				.expected_csid = NAN_CS_SK_CCM_128,
+				.term_once_connected = 1,
+			},
+		},
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+		},
+	}
+};
+
+static struct nan_test_case four_way_ndp_two_way_ndl_chan_149_gcm_256 = {
+	.name = "Four way NDP and three way NDL with GCMP 256",
+	.pub_conf = {
+		.schedule_cb = nan_test_schedule_cb_all_ndc,
+		.get_chans_cb = nan_test_get_chans_default,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_CONNECTED,
+				.csid = NAN_CS_SK_GCM_256,
+				.expected_csid = NAN_CS_SK_GCM_256,
+			},
+		},
+		.pot_avail = {
+			0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,
+			0xba, 0x02, 0x20, 0x02, 0x04
+		},
+		.pot_avail_len = 13,
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+		},
+	},
+	.sub_conf  = {
+		.schedule_cb = nan_test_schedule_cb_2ghz_no_ndc,
+		.schedule_conf_cb = nan_test_schedule_cb_all_ndc,
+		.get_chans_cb = nan_test_get_chans_default_reverse,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_CONNECTED,
+				.csid = NAN_CS_SK_GCM_256,
+				.expected_csid = NAN_CS_SK_GCM_256,
+				.term_once_connected = 1,
+			},
+		},
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+		},
+	}
+};
+
+
+static struct nan_test_case pmk_mismatch = {
+	.name = "PMK mismatch test case",
+	.pub_conf = {
+		.schedule_cb = nan_test_schedule_cb_all_ndc,
+		.get_chans_cb = nan_test_get_chans_default,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_DISCONNECTED,
+				.csid = NAN_CS_SK_GCM_256,
+			},
+		},
+		.pot_avail = {
+			0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,
+			0xba, 0x02, 0x20, 0x02, 0x04
+		},
+		.pot_avail_len = 13,
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+		},
+	},
+	.sub_conf  = {
+		.schedule_cb = nan_test_schedule_cb_all_no_ndc,
+		.get_chans_cb = nan_test_get_chans_default,
+		.n_ndps = 1,
+		.ndp_confs = {
+			{
+				.accept_request = 1,
+				.expected_result =
+					NAN_TEST_NDP_NOTIFY_DISCONNECTED,
+				.csid = NAN_CS_SK_GCM_256,
+			},
+		},
+		.pmk = {
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x0,
+		},
+	}
+};
+
+
 static struct nan_test_case *g_nan_test_cases[] = {
 	&three_way_ndp_two_way_ndl_chan_149,
 	&three_way_ndp_two_way_ndl_diff_period,
@@ -382,6 +532,9 @@ static struct nan_test_case *g_nan_test_cases[] = {
 	&three_way_ndp_two_way_ndl_chan_mis,
 	&three_way_ndp_two_way_ndl_reject,
 	&three_way_ndp_three_way_ndl,
+	&four_way_ndp_two_way_ndl_chan_149_ccm_128,
+	&four_way_ndp_two_way_ndl_chan_149_gcm_256,
+	&pmk_mismatch,
 	NULL,
 };
 
diff --git a/src/nan/nan_module_tests.c b/src/nan/nan_module_tests.c
index dedec5b612..3ccce9243d 100644
--- a/src/nan/nan_module_tests.c
+++ b/src/nan/nan_module_tests.c
@@ -78,6 +78,8 @@ struct nan_test_ndp_notify {
 	size_t ssi_len;
 };
 
+#define NAN_TEST_MAX_TKS 2
+
 /*
  * nan_test_global - Global context for the NAN testing
  *
@@ -384,6 +386,10 @@ static int nan_ndp_notify_action(struct nan_device *dev, void *ctx)
 			dev->conf->schedule_cb(&params->sched);
 			params->sched.elems = dev->global->elems;
 			params->sched_valid = 1;
+
+			params->sec.csid =
+				dev->conf->ndp_confs[dev->n_ndps].csid;
+			os_memcpy(params->sec.pmk, dev->conf->pmk, PMK_LEN);
 		} else {
 			wpa_printf(MSG_INFO, "%s: Rejecting request",
 				   dev->name);
@@ -437,6 +443,9 @@ static int nan_ndp_notify_action(struct nan_device *dev, void *ctx)
 			params->sched.elems = dev->global->elems;
 			params->sched_valid = 1;
 
+			params->sec.csid =
+				dev->conf->ndp_confs[dev->n_ndps].csid;
+			os_memcpy(params->sec.pmk, dev->conf->pmk, PMK_LEN);
 		} else {
 			wpa_printf(MSG_INFO, "%s: Rejecting response",
 				   dev->name);
@@ -606,6 +615,19 @@ static void nan_test_ndp_connected_cb(void *ctx,
 	nan_peer_get_pot_avail(dev->nan, params->ndp_id.peer_nmi,
 			       &pot);
 
+	if (nan_peer_get_tk(dev->nan, params->ndp_id.peer_nmi,
+			    params->peer_ndi, params->local_ndi,
+			    dev->tk, &dev->tk_len, &dev->csid) == 0) {
+		wpa_hexdump(MSG_DEBUG, "NAN Test: TK", dev->tk, dev->tk_len);
+
+		if (dev->csid != dev->conf->ndp_confs[dev->n_ndps].expected_csid) {
+			wpa_printf(MSG_ERROR,
+				   "%s: Unexpected CSID: got %u expected %u",
+				   dev->name, dev->csid,
+				   dev->conf->ndp_confs[dev->n_ndps].expected_csid);
+		}
+	}
+
 	nan_test_ndp_action(dev, NAN_TEST_NDP_NOTIFY_CONNECTED,
 			    &params->ndp_id, 0,
 			    params->ssi, params->ssi_len,
@@ -849,6 +871,7 @@ static int nan_test_dev_init(struct nan_device *dev)
 	struct nan_config nan;
 
 	os_memset(&nan, 0, sizeof(nan));
+	os_memcpy(nan.nmi_addr, dev->nmi, ETH_ALEN);
 	nan.cb_ctx = dev;
 
 	nan.start = nan_test_start_cb;
@@ -1005,6 +1028,8 @@ static int nan_test_ndp_request(struct nan_device *sub)
 	params->ndp_id.id = ++sub->counter;
 	params->qos.min_slots = NAN_TEST_MIN_SLOTS;
 	params->qos.max_latency = NAN_TEST_MAX_LATENCY;
+	params->sec.csid = sub->conf->ndp_confs[sub->n_ndps].csid;
+	os_memcpy(params->sec.pmk, sub->conf->pmk, PMK_LEN);
 
 	/* Use the device specific schedule callback */
 	sub->conf->schedule_cb(&params->sched);
@@ -1079,16 +1104,43 @@ static int nan_test_verify_expected_result(struct nan_device *dev)
 static int nan_test_iteration_done(struct nan_test_global *global)
 {
 	struct nan_device *dev;
+	u8 tk[NAN_TK_MAX_LEN];
+	size_t tk_len = 0;
+	enum nan_cipher_suite_id csid;
 	int ret;
 
+	os_memset(tk, 0, sizeof(tk));
+
 	dl_list_for_each(dev, &global->devs, struct nan_device, list) {
 		ret = nan_test_verify_expected_result(dev);
 
 		if (ret)
 			return ret;
 
+		if (tk_len == 0 && dev->tk_len > 0) {
+			os_memcpy(tk, dev->tk, dev->tk_len);
+			tk_len = dev->tk_len;
+			csid = dev->csid;
+		} else if (dev->tk_len > 0) {
+			if (tk_len != dev->tk_len ||
+			    csid != dev->csid ||
+			    os_memcmp(tk, dev->tk, tk_len) != 0) {
+				wpa_printf(MSG_ERROR,
+					   "%s: TK mismatch with other device",
+					   dev->name);
+				return -1;
+			}
+
+			wpa_printf(MSG_INFO, "%s: TK matches with other device",
+				   dev->name);
+		}
+
 		dev->connected_notify_received = false;
 		dev->disconnected_notify_received = false;
+
+		os_memset(dev->tk, 0, sizeof(dev->tk));
+		dev->tk_len = 0;
+
 		dev->n_ndps++;
 	}
 
diff --git a/src/nan/nan_module_tests.h b/src/nan/nan_module_tests.h
index f50eb76953..18eab97f9e 100644
--- a/src/nan/nan_module_tests.h
+++ b/src/nan/nan_module_tests.h
@@ -57,6 +57,11 @@ enum nan_test_ndp_notify_type {
  * @term_once_connected: Terminate once connected.
  * @expected_result: Expected NDP establishment result
  * @reason: For publisher device, indicates the reject reason
+ * @pot_avail: Device potential availability
+ * @pot_avail_len: Length of the device potential availability
+ * @csid: Cipher suite ID
+ * @expected_csid: Expected Cipher suite ID in case of a successful connection
+ * @pmk: Pairwise Master Key
  */
 struct nan_test_dev_conf {
 	int (*schedule_cb)(struct nan_schedule *sched);
@@ -72,7 +77,11 @@ struct nan_test_dev_conf {
 		bool term_once_connected;
 		enum nan_test_ndp_notify_type expected_result;
 		u8 reason;
+		enum nan_cipher_suite_id csid;
+		enum nan_cipher_suite_id expected_csid;
 	} ndp_confs[NAN_MAX_NUM_NDPS];
+
+	u8 pmk[PMK_LEN];
 };
 
 /*
@@ -92,6 +101,9 @@ struct nan_test_dev_conf {
  *     was received
  * @disconnected_notify_received: Indicates whether a disconnected notification
  *     was received
+ * @tk: NAN TK
+ * @tk_len: Length of the NAN TK
+ * @csid: Cipher suite ID
  */
 struct nan_device {
 	struct dl_list list;
@@ -111,6 +123,10 @@ struct nan_device {
 
 	bool connected_notify_received;
 	bool disconnected_notify_received;
+
+	u8 tk[NAN_TK_MAX_LEN];
+	size_t tk_len;
+	enum nan_cipher_suite_id csid;
 };
 
 /*
-- 
2.49.0




More information about the Hostap mailing list