get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.0/patches/2198757/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2198757,
    "url": "http://patchwork.ozlabs.org/api/1.0/patches/2198757/?format=api",
    "project": {
        "id": 22,
        "url": "http://patchwork.ozlabs.org/api/1.0/projects/22/?format=api",
        "name": "HostAP Development",
        "link_name": "hostap",
        "list_id": "hostap.lists.infradead.org",
        "list_email": "hostap@lists.infradead.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260219202514.5781-56-andrei.otcheretianski@intel.com>",
    "date": "2026-02-19T20:25:11",
    "name": "[55/58] NAN: Add test utility for NAN module",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "2ea0c95eea498935921515c84918ff39d1c08dc5",
    "submitter": {
        "id": 62065,
        "url": "http://patchwork.ozlabs.org/api/1.0/people/62065/?format=api",
        "name": "Andrei Otcheretianski",
        "email": "andrei.otcheretianski@intel.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/hostap/patch/20260219202514.5781-56-andrei.otcheretianski@intel.com/mbox/",
    "series": [
        {
            "id": 492721,
            "url": "http://patchwork.ozlabs.org/api/1.0/series/492721/?format=api",
            "date": "2026-02-19T20:24:21",
            "name": "NAN: Add NAN Data Path (NDP) support",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/492721/mbox/"
        }
    ],
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2198757/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=lists.infradead.org header.i=@lists.infradead.org\n header.a=rsa-sha256 header.s=bombadil.20210309 header.b=G8ZLf0H1;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n secure) header.d=infradead.org header.i=@infradead.org header.a=rsa-sha256\n header.s=desiato.20200630 header.b=M/ZKLoii;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256\n header.s=Intel header.b=OaXDWv1U;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=none (no SPF record) smtp.mailfrom=lists.infradead.org\n (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org;\n envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from bombadil.infradead.org (bombadil.infradead.org\n [IPv6:2607:7c80:54:3::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fHjDk0lnnz1xwg\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 21 Feb 2026 07:54:57 +1100 (AEDT)",
            "from localhost ([::1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vtXVp-0000000Fav6-3Uia;\n\tFri, 20 Feb 2026 20:54:09 +0000",
            "from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05])\n\tby bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vtAdN-0000000BzLj-0gL1\n\tfor hostap@bombadil.infradead.org;\n\tThu, 19 Feb 2026 20:28:27 +0000",
            "from mgamail.intel.com ([198.175.65.18])\n\tby desiato.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vtAd8-00000001qIK-2uRm\n\tfor hostap@lists.infradead.org;\n\tThu, 19 Feb 2026 20:28:20 +0000",
            "from orviesa004.jf.intel.com ([10.64.159.144])\n  by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 19 Feb 2026 12:28:07 -0800",
            "from aotchere-mobl1.ger.corp.intel.com (HELO\n aotchere-mobl1.intel.com) ([10.245.246.171])\n  by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 19 Feb 2026 12:28:04 -0800"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20210309; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=ynBEPya1PWeVt/JKYhhQkfbRHqC3c7iosVdxdtn2m5U=; b=G8ZLf0H1k7s1Vt\n\tFjp0DI2kvkTUDs1DT/GHbdTWJ1fezPYwF7CXZTQYhGwZFLQ9vuHu7q0+CbyrHFREF1xG05kZ4zC4j\n\t6eiYOR+6sncAH2n8LnL3+vrDZ/fwpXoO5SbLTVSdNLT5DuFacH2YGz/WmHjzyyaLq6OAqDP4Ewgqy\n\tj4s9gqWqmEq0RCVKG0YcGthxgi1T98x7gaDg8/j/2/VnAlIm35ELjaPfvvPrNTbmbMvmYkaNh+iAJ\n\txSyb0QX0asFO6xociF5XD29SbJsRZQc6Wu8sh4Vkp2v3zJLQWDMHxPVm3cB3Cw2T9tgRjNIK0BDZ6\n\tbTu7IfgUja0Dh8Cwam1A==;",
            "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=infradead.org; s=desiato.20200630; h=Content-Transfer-Encoding:MIME-Version\n\t:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:\n\tContent-Type:Content-ID:Content-Description;\n\tbh=dM/rVkJvXdBUBf878k/A4KaOVKq/lQAtbZDbItrs9eA=; b=M/ZKLoiiMWdkg6TtJPx1bpIRB3\n\tf1is8DZN/hLi0svICO51PzhuzZJ3kgvrNLdzAUS1cMbnuyhOaE3FNwjkmHMm6LQK0uBcmhJvfCSnJ\n\tJL6Ad86pKCMBactHFPWoFAaA8n1VpJEaA38gTHurZzhT651oMhYGM1k+aO9G/POyM5Dg1cAAkqChb\n\tqvDJFDs5BlJgh9Ib2wwZs5CNu/TLbNBfqN1f2WZzp5B5Y+u4GaHZE7E2gNAnSVTl1X09+uwMdNvg9\n\toaVc9ihll4oV9oiYGUEbDaAX++/abxVI/rhek1c9zaeO6n3eyvL1Qqt49BaIDki30ukytNmA+6y5F\n\tWk+TiRVw==;",
            "v=1; a=rsa-sha256; c=relaxed/simple;\n  d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n  t=1771532891; x=1803068891;\n  h=from:to:cc:subject:date:message-id:in-reply-to:\n   references:mime-version:content-transfer-encoding;\n  bh=8NSGwzUGlj8+hQUyfxMlWVhnTDuV0lU0iGmDI52cjSM=;\n  b=OaXDWv1UcsTAl4Nzi0n9WgAZf5BsG0xwEPA1ibCB+HsLKmEyemglyiVc\n   szbxxoepeA2QrKF4spVm27JBKkGaqRwMKswtualg1WWWb3wmD6GrHJlJO\n   lg9MFpijQgQF6YZYqiIhq+lT7hpCrpxfcVGcUEgrQQfXzNA/us717W/Ah\n   dUiNTaX9nHqwt1q9fxSnry+NURHAmWqt9ORwBJg+O6TJ0x32ojgVnAril\n   TDW0HKYKVH0q90toGwStq4YgjDpqF7KzMCYsqVvbiELOX5VrpBNggQ/Ej\n   zoVBIpXgkl9+fgWRwd7IEniJ2RSGKo1vagaRFTxYN8zMLiT0kySCGRH4S\n   Q==;"
        ],
        "X-CSE-ConnectionGUID": [
            "8y9KNv+aRDuW3g06vKl/gg==",
            "sctlH1+EQHmDYwz4elek2w=="
        ],
        "X-CSE-MsgGUID": [
            "54sCcI/MTOOn68zBDItWAg==",
            "dUGchQr2RPqwh1uYX50kqQ=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6800,10657,11706\"; a=\"72674099\"",
            "E=Sophos;i=\"6.21,300,1763452800\";\n   d=\"scan'208\";a=\"72674099\"",
            "E=Sophos;i=\"6.21,300,1763452800\";\n   d=\"scan'208\";a=\"219154140\""
        ],
        "X-ExtLoop1": "1",
        "From": "Andrei Otcheretianski <andrei.otcheretianski@intel.com>",
        "To": "hostap@lists.infradead.org,\n\tvamsin@qti.qualcomm.com,\n\tvganneva@qti.qualcomm.com,\n\tmaheshkkv@google.com",
        "Cc": "Ilan Peer <ilan.peer@intel.com>",
        "Subject": "[PATCH 55/58] NAN: Add test utility for NAN module",
        "Date": "Thu, 19 Feb 2026 22:25:11 +0200",
        "Message-ID": "<20260219202514.5781-56-andrei.otcheretianski@intel.com>",
        "X-Mailer": "git-send-email 2.52.0",
        "In-Reply-To": "<20260219202514.5781-1-andrei.otcheretianski@intel.com>",
        "References": "<20260219202514.5781-1-andrei.otcheretianski@intel.com>",
        "MIME-Version": "1.0",
        "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ",
        "X-CRM114-CacheID": "sfid-20260219_202813_578260_EDCF38BF ",
        "X-CRM114-Status": "GOOD (  25.56  )",
        "X-Spam-Score": "-0.9 (/)",
        "X-Spam-Report": "Spam detection software,\n running on the system \"desiato.infradead.org\",\n has NOT identified this incoming email as spam.  The original\n message has been attached to this so you can view it or label\n similar future email.  If you have any questions, see\n the administrator of that system for details.\n Content preview:  From: Ilan Peer <ilan.peer@intel.com> The main motivation\n   of the utility is to be able to test NAN NDP/NDL state machine transitions.\n    Signed-off-by: Ilan Peer <ilan.peer@intel.com> ---\n src/nan/nan_module_test_cases.c\n    | 398 ++++++++++ src/nan/nan_module_tests.c | 1164\n ++++++++++++++++++++++++++++\n    src/nan/nan_module_tests.h | 129 +++ [...]\n Content analysis details:   (-0.9 points, 5.0 required)\n  pts rule name              description\n ---- ----------------------\n --------------------------------------------------\n -0.7 RCVD_IN_DNSWL_LOW      RBL: Sender listed at https://www.dnswl.org/, low\n                             trust\n                             [198.175.65.18 listed in list.dnswl.org]\n  0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to\n                              Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                             [198.175.65.18 listed in sa-accredit.habeas.com]\n  0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The\n                             query to Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                          [198.175.65.18 listed in\n sa-trusted.bondedsender.org]\n  0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to\n                              Validity was blocked.  See\n                             https://knowledge.validity.com/hc/en-us/articles/20961730681243\n                              for more information.\n                             [198.175.65.18 listed in\n bl.score.senderscore.com]\n -0.0 SPF_PASS               SPF: sender matches SPF record\n  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record\n -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from\n author's\n                             domain\n -0.1 DKIM_VALID             Message has at least one valid DKIM or DK\n signature\n -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from\n                             envelope-from domain\n  0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n not necessarily valid\n -0.0 DKIMWL_WL_HIGH         DKIMwl.org - High trust sender",
        "X-Mailman-Approved-At": "Fri, 20 Feb 2026 12:54:05 -0800",
        "X-BeenThere": "hostap@lists.infradead.org",
        "X-Mailman-Version": "2.1.34",
        "Precedence": "list",
        "List-Id": "<hostap.lists.infradead.org>",
        "List-Unsubscribe": "<http://lists.infradead.org/mailman/options/hostap>,\n <mailto:hostap-request@lists.infradead.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.infradead.org/pipermail/hostap/>",
        "List-Post": "<mailto:hostap@lists.infradead.org>",
        "List-Help": "<mailto:hostap-request@lists.infradead.org?subject=help>",
        "List-Subscribe": "<http://lists.infradead.org/mailman/listinfo/hostap>,\n <mailto:hostap-request@lists.infradead.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "\"Hostap\" <hostap-bounces@lists.infradead.org>",
        "Errors-To": "hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"
    },
    "content": "From: Ilan Peer <ilan.peer@intel.com>\n\nThe main motivation of the utility is to be able to test\nNAN NDP/NDL state machine transitions.\n\nSigned-off-by: Ilan Peer <ilan.peer@intel.com>\n---\n src/nan/nan_module_test_cases.c    |  398 ++++++++++\n src/nan/nan_module_tests.c         | 1164 ++++++++++++++++++++++++++++\n src/nan/nan_module_tests.h         |  129 +++\n src/utils/module_tests.h           |    1 +\n wpa_supplicant/Makefile            |    4 +\n wpa_supplicant/wpas_module_tests.c |    5 +\n 6 files changed, 1701 insertions(+)\n create mode 100644 src/nan/nan_module_test_cases.c\n create mode 100644 src/nan/nan_module_tests.c\n create mode 100644 src/nan/nan_module_tests.h",
    "diff": "diff --git a/src/nan/nan_module_test_cases.c b/src/nan/nan_module_test_cases.c\nnew file mode 100644\nindex 0000000000..43e08d34b4\n--- /dev/null\n+++ b/src/nan/nan_module_test_cases.c\n@@ -0,0 +1,398 @@\n+/*\n+ * nan_test - NAN NDP state machine test cases\n+ * Copyright (C) 2025 Intel Corporation\n+ *\n+ * This software may be distributed under the terms of the BSD license.\n+ * See README for more details.\n+ */\n+\n+#include \"nan_module_tests.h\"\n+\n+static u8 default_bitmap[] = {0xfe, 0xff, 0xfe, 0xff};\n+\n+static void nan_test_schedule_cb(struct nan_schedule *sched, bool ndc,\n+\t\t\t\t int freq, int center_freq1, int center_freq2,\n+\t\t\t\t int bandwidth)\n+{\n+\tos_memset(sched, 0, sizeof(*sched));\n+\n+\t/* Only map ID 0 is used */\n+\tsched->map_ids_bitmap = 0x1;\n+\n+\tsched->n_chans = 1;\n+\tsched->chans[0].chan.freq = freq;\n+\tsched->chans[0].chan.center_freq1 = center_freq1;\n+\tsched->chans[0].chan.center_freq2 = center_freq2;\n+\tsched->chans[0].chan.bandwidth = bandwidth;\n+\n+\tsched->chans[0].committed.duration = 0;\n+\tsched->chans[0].committed.period = 3;\n+\tsched->chans[0].committed.offset = 0;\n+\tsched->chans[0].committed.len = sizeof(default_bitmap);\n+\tos_memcpy(sched->chans[0].committed.bitmap,\n+\t\t  default_bitmap,\n+\t\t  sizeof(default_bitmap));\n+\n+\tsched->chans[0].map_id = 0;\n+\n+\tif (!ndc)\n+\t\treturn;\n+\n+\tos_memset(&sched->ndc, 0, sizeof(sched->ndc));\n+\tsched->ndc.duration = 0;\n+\tsched->ndc.period = 3;\n+\tsched->ndc.offset = 0;\n+\tsched->ndc.len = 1;\n+\tsched->ndc.bitmap[0] = 0xfe;\n+}\n+\n+\n+static int nan_test_schedule_cb_all_ndc(struct nan_schedule *sched)\n+{\n+\tstatic u8 seq_id = 1;\n+\n+\tnan_test_schedule_cb(sched, true, 5745, 5745, true, 20);\n+\tsched->sequence_id = ++seq_id;\n+\treturn 0;\n+}\n+\n+static int nan_test_schedule_cb_all_no_ndc(struct nan_schedule *sched)\n+{\n+\tstatic u8 seq_id = 1;\n+\n+\tnan_test_schedule_cb(sched, false, 5745, 5745, 0, 20);\n+\tsched->sequence_id = ++seq_id;\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_schedule_cb_all_no_ndc_period_4(struct nan_schedule *sched)\n+{\n+\tstatic u8 seq_id = 1;\n+\n+\tnan_test_schedule_cb(sched, false, 5745, 5745, 0, 20);\n+\n+\t/*\n+\t * Modify the map to have a period or 1024 TUs (both halfs are\n+\t * identical\n+\t */\n+\tsched->chans[0].committed.period = 4;\n+\tsched->chans[0].committed.len += sizeof(default_bitmap);\n+\tos_memcpy(sched->chans[0].committed.bitmap + sizeof(default_bitmap),\n+\t\t  default_bitmap,\n+\t\t  sizeof(default_bitmap));\n+\n+\tsched->sequence_id = ++seq_id;\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_schedule_cb_2ghz_no_ndc(struct nan_schedule *sched)\n+{\n+\tstatic u8 seq_id = 1;\n+\n+\tnan_test_schedule_cb(sched, false, 2437, 2437, 0, 20);\n+\tsched->sequence_id = ++seq_id;\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_get_chans_default(struct nan_channels *chans)\n+{\n+\tchans->n_chans = 2;\n+\tchans->chans = os_zalloc(sizeof(struct nan_channel_info) *\n+\t\t\t\t chans->n_chans);\n+\tif (!chans->chans)\n+\t\treturn -1;\n+\n+\tchans->chans[0].channel = 6;\n+\tchans->chans[0].op_class = 81;\n+\tchans->chans[0].pref = 255;\n+\n+\tchans->chans[1].channel = 149;\n+\tchans->chans[1].op_class = 126;\n+\tchans->chans[1].pref = 254;\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_get_chans_default_reverse(struct nan_channels *chans)\n+{\n+\tchans->n_chans = 2;\n+\tchans->chans = os_zalloc(sizeof(struct nan_channel_info) *\n+\t\t\t\t chans->n_chans);\n+\tif (!chans->chans)\n+\t\treturn -1;\n+\n+\tchans->chans[0].channel = 149;\n+\tchans->chans[0].op_class = 126;\n+\tchans->chans[0].pref = 255;\n+\n+\tchans->chans[1].channel = 6;\n+\tchans->chans[1].op_class = 81;\n+\tchans->chans[1].pref = 254;\n+\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_get_chans_default_24g(struct nan_channels *chans)\n+{\n+\tchans->n_chans = 1;\n+\tchans->chans = os_zalloc(sizeof(struct nan_channel_info) *\n+\t\t\t\t chans->n_chans);\n+\tif (!chans->chans)\n+\t\treturn -1;\n+\n+\tchans->chans[0].channel = 6;\n+\tchans->chans[0].op_class = 81;\n+\tchans->chans[0].pref = 255;\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_get_chans_default_52g(struct nan_channels *chans)\n+{\n+\tchans->n_chans = 1;\n+\tchans->chans = os_zalloc(sizeof(struct nan_channel_info) *\n+\t\t\t\t chans->n_chans);\n+\tif (!chans->chans)\n+\t\treturn -1;\n+\n+\tchans->chans[0].channel = 149;\n+\tchans->chans[0].op_class = 126;\n+\tchans->chans[0].pref = 255;\n+\treturn 0;\n+}\n+\n+\n+static struct nan_test_case three_way_ndp_two_way_ndl_chan_149 = {\n+\t.name = \"Three way NDP and two way NDL channel 149\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_no_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+\n+static struct nan_test_case three_way_ndp_two_way_ndl_diff_period = {\n+\t.name = \"Three way NDP and two way NDL channel 149. Subscriber period=4\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_no_ndc_period_4,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+static struct nan_test_case three_way_ndp_two_way_ndl_chan_6 = {\n+\t.name = \"Three way NDP and two way NDL channel 6\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_no_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default_24g,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.term_once_connected = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+static struct nan_test_case three_way_ndp_two_way_ndl_chan_mis = {\n+\t.name = \"Three way NDP and two way NDL channel mismatch\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default_52g,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_2ghz_no_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default_24g,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+static struct nan_test_case three_way_ndp_three_way_ndl = {\n+\t.name = \"Three way NDP and three way NDL\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_2ghz_no_ndc,\n+\t\t.schedule_conf_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default_reverse,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 1,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t\t.term_once_connected = 1,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+static struct nan_test_case three_way_ndp_two_way_ndl_reject = {\n+\t.name = \"Three way NDP and two way NDL rejected\",\n+\t.pub_conf = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+\t\t\t\t.reason = NAN_REASON_NDP_REJECTED,\n+\t\t\t},\n+\t\t},\n+\t\t.pot_avail = {\n+\t\t\t0x12, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00,\n+\t\t\t0xba, 0x02, 0x20, 0x02, 0x04\n+\t\t},\n+\t\t.pot_avail_len = 13,\n+\t},\n+\t.sub_conf  = {\n+\t\t.schedule_cb = nan_test_schedule_cb_all_no_ndc,\n+\t\t.get_chans_cb = nan_test_get_chans_default,\n+\t\t.n_ndps = 1,\n+\t\t.ndp_confs = {\n+\t\t\t{\n+\t\t\t\t.accept_request = 0,\n+\t\t\t\t.expected_result =\n+\t\t\t\t\tNAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+\t\t\t},\n+\t\t},\n+\t}\n+};\n+\n+\n+static struct nan_test_case *g_nan_test_cases[] = {\n+\t&three_way_ndp_two_way_ndl_chan_149,\n+\t&three_way_ndp_two_way_ndl_diff_period,\n+\t&three_way_ndp_two_way_ndl_chan_6,\n+\t&three_way_ndp_two_way_ndl_chan_mis,\n+\t&three_way_ndp_two_way_ndl_reject,\n+\t&three_way_ndp_three_way_ndl,\n+\tNULL,\n+};\n+\n+\n+struct nan_test_case *nan_test_case_get_next(void)\n+{\n+\tstatic u32 nan_test_case_idx = 0;\n+\tstruct nan_test_case *curr = g_nan_test_cases[nan_test_case_idx];\n+\n+\tif (curr)\n+\t\tnan_test_case_idx++;\n+\n+\treturn curr;\n+}\ndiff --git a/src/nan/nan_module_tests.c b/src/nan/nan_module_tests.c\nnew file mode 100644\nindex 0000000000..468ef90083\n--- /dev/null\n+++ b/src/nan/nan_module_tests.c\n@@ -0,0 +1,1164 @@\n+/*\n+ * NAN NDP/NDL state machine testing\n+ * Copyright (C) 2025 Intel Corporation\n+ *\n+ * This software may be distributed under the terms of the BSD license.\n+ * See README for more details.\n+ */\n+\n+#include \"nan_module_tests.h\"\n+\n+#define NAN_TEST_MAX_NAF_LEN     1024\n+#define NAN_TEST_MAX_PEERS       20\n+#define NAN_TEST_MAX_ACTIONS     30\n+#define NAN_TEST_MIN_SLOTS       12\n+#define NAN_TEST_MAX_LATENCY     3\n+#define NAN_TEST_PUBLISH_INST_ID 12\n+\n+static const u8 pub_nmi[] = {0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};\n+static const u8 pub_ndi[] = {0x00, 0xAA, 0xAA, 0x00, 0x00, 0x00};\n+static const u8 sub_nmi[] = {0x00, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};\n+static const u8 sub_ndi[] = {0x00, 0xBB, 0xBB, 0xBB, 0x00, 0x00};\n+\n+/*\n+ * struct nan_test_action - NAN test action context\n+ *\n+ * @list: Used for global actions list\n+ * @dev: NAN device for which the action is intended\n+ * @cb: Callback to be called for the action\n+ * @ctx: Parameter for the callback function\n+ *\n+ * The test utility uses actions to handle asynchronous events between the\n+ * devices and internally to the local device. When an event is triggered\n+ * outside of the NAN module context, the event is wrapped by an action item and\n+ * is processed asynchronously. Examples:\n+ *\n+ * NAF transmission: when a NAF is transmitted by a device, it is translated to\n+ * 2 asynchronous actions: one action to indicate Tx status to the transmitting\n+ * device and one to indicate an Rx frame to the peer device.\n+ *\n+ * NDP event: when an NDP event is fired by the NAN module, it is translated to\n+ * an asynchronous action to the local device.\n+ */\n+struct nan_test_action {\n+\tstruct dl_list list;\n+\tstruct nan_device *dev;\n+\tint (*cb)(struct nan_device *dev, void *ctx);\n+\tvoid *ctx;\n+};\n+\n+/*\n+ * nan_test_tx_status_action - NAN test Tx status action context\n+ *\n+ * @data: Copy of the original NAF\n+ * @acked: True iff the NAF was acked\n+ * @dst: Destination of the NAF\n+ */\n+struct nan_test_tx_status_action {\n+\tconst struct wpabuf *data;\n+\tbool acked;\n+\tu8 dst[ETH_ALEN];\n+};\n+\n+/*\n+ * nan_test_ndp_notify - NAN test NDP notification handling\n+ *\n+ * @type: Notification type\n+ * @ndp_id: NDP identifier\n+ * @ssi: Service specific information\n+ * @ssi_len: Length of service specific information\n+ */\n+struct nan_test_ndp_notify {\n+\tenum nan_test_ndp_notify_type type;\n+\tstruct nan_ndp_id ndp_id;\n+\tconst u8 *ssi;\n+\tsize_t ssi_len;\n+};\n+\n+/*\n+ * nan_test_global - Global context for the NAN testing\n+ *\n+ * @devs: List of devices. See &struct nan_device.\n+ * @actions: tracks the NAN actions\n+ * @elems: Default HT/VHT/HE capabilities elements\n+ */\n+struct nan_test_global {\n+\tstruct dl_list devs;\n+\tstruct dl_list actions;\n+\tstruct wpabuf *elems;\n+};\n+\n+#define DEV_NOT_INIT_ERR(_dev)                                        \\\n+do {                                                                  \\\n+\tif (!(_dev) || !(_dev)->nan)  {                               \\\n+\t\twpa_printf(MSG_ERROR,                                 \\\n+\t\t\t   \"NAN: %s: device not initialized\",         \\\n+\t\t\t   __func__);                                 \\\n+\t\treturn -1;                                            \\\n+\t}                                                             \\\n+} while (0)\n+\n+#define DEV_NOT_INIT_ERR_VOID(_dev)                                   \\\n+do {                                                                  \\\n+\tif (!(_dev) || !(_dev)->nan)  {                               \\\n+\t\twpa_printf(MSG_ERROR,                                 \\\n+\t\t\t   \"NAN: %s: device not initialized\",         \\\n+\t\t\t   __func__);                                 \\\n+\t\treturn;                                               \\\n+\t}                                                             \\\n+} while (0)\n+\n+/*\n+ * nan_test_global_init - Initialize NAN test global data structures\n+ *\n+ * @global: NAN test global data structure\n+ */\n+static void nan_test_global_init(struct nan_test_global *global)\n+{\n+\tu8 elems[] = {\n+\t\t/* HT capabilities */\n+\t\t0x2d, 0x1a, 0x7e, 0x10, 0x1b, 0xff, 0xff, 0x00,\n+\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n+\t\t0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n+\t\t0x00, 0x00, 0x00, 0x00,\n+\n+\t\t/* VHT capabilities */\n+\t\t0xbf, 0x0c, 0xfa, 0x04, 0x80, 0x03, 0xaa, 0xaa,\n+\t\t0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,\n+\n+\t\t/* HE capabilities */\n+\t\t0xff, 0x1e, 0x23, 0x01, 0x78, 0xc8, 0x1a, 0x40,\n+\t\t0x00, 0x1c, 0xbf, 0xce, 0x00, 0x00, 0x00, 0x00,\n+\t\t0x00, 0x00, 0x00, 0x00, 0xfa, 0xff, 0xfa, 0xff,\n+\t\t0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff,\n+\t};\n+\n+\twpa_printf(MSG_INFO, \"%s: Enter\", __func__);\n+\tos_memset(global, 0, sizeof(struct nan_test_global));\n+\tdl_list_init(&global->devs);\n+\tdl_list_init(&global->actions);\n+\n+\tglobal->elems = wpabuf_alloc(sizeof(elems));\n+\twpabuf_put_data(global->elems, elems, sizeof(elems));\n+\n+\twpa_printf(MSG_INFO, \"%s: Done\\n\", __func__);\n+}\n+\n+\n+/*\n+ * nan_test_dev_deinit - De-initialize NAN device\n+ *\n+ * @dev: NAN device\n+ */\n+static void nan_test_dev_deinit(struct nan_device *dev)\n+{\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\tos_free(dev->pot_avail);\n+\tnan_stop(dev->nan);\n+\tnan_deinit(dev->nan);\n+\tos_memset(dev, 0, sizeof(struct nan_device));\n+}\n+\n+\n+/*\n+ * nan_test_global_deinit - De-initialize NAN test global data structures\n+ *\n+ * @global: NAN test global data structure\n+ */\n+static void nan_test_global_deinit(struct nan_test_global *global)\n+{\n+\tstruct nan_device *dev, *next;\n+\tstruct nan_test_action *action, *action_next;\n+\n+\twpa_printf(MSG_INFO, \"%s: Enter\", __func__);\n+\n+\tdl_list_for_each_safe(dev, next, &global->devs, struct nan_device,\n+\t\t\t      list) {\n+\t\tdl_list_del(&dev->list);\n+\t\tnan_test_dev_deinit(dev);\n+\t\tos_free(dev);\n+\t}\n+\n+\tdl_list_for_each_safe(action, action_next, &global->actions,\n+\t\t\t      struct nan_test_action, list) {\n+\t\tdl_list_del(&dev->list);\n+\t\tos_free(action->ctx);\n+\t\tos_free(action);\n+\t}\n+\n+\twpabuf_free(global->elems);\n+}\n+\n+\n+/*\n+ * nan_test_add_action - Add a NAN test action to the list of actions\n+ *\n+ * @global: NAN test global data structure\n+ * @dev: NAN device for which the action is intended\n+ * @cb: Callback to be called for the action\n+ * @ctx: Parameter for the callback function\n+ * Returns a pointer to the newly added action, or NULL on failure\n+ */\n+static struct nan_test_action *\n+nan_test_add_action(struct nan_test_global *global,\n+\t\t    struct nan_device *dev,\n+\t\t    int (*cb)(struct nan_device *dev, void *ctx),\n+\t\t    void *ctx)\n+{\n+\tstruct nan_test_action *action;\n+\n+\taction = os_malloc(sizeof(struct nan_test_action));\n+\tif (!action) {\n+\t\twpa_printf(MSG_ERROR, \"NAN Test: Failed to allocate action\");\n+\t\treturn NULL;\n+\t}\n+\n+\taction->dev = dev;\n+\taction->cb = cb;\n+\taction->ctx = ctx;\n+\n+\tdl_list_add_tail(&global->actions, &action->list);\n+\treturn action;\n+}\n+\n+\n+/*\n+ * nan_test_run_actions - Iterate over all NAN test actions and execute them\n+ * @global: NAN test global data structure\n+ * return 0 in success, -1 on error.\n+ *\n+ * Runs as longs as there are actions to run. Exists where there are no more\n+ * action to perform or on error.\n+ */\n+static int nan_test_run_actions(struct nan_test_global *global)\n+{\n+\tu32 n_actions = 0;\n+\n+\twpa_printf(MSG_INFO, \"%s: Running actions\", __func__);\n+\n+\twhile (!dl_list_empty(&global->actions)) {\n+\t\tstruct nan_test_action *action =\n+\t\t\tdl_list_first(&global->actions, struct nan_test_action,\n+\t\t\t\t      list);\n+\t\tint ret;\n+\n+\t\tdl_list_del(&action->list);\n+\n+\t\tif (++n_actions > NAN_TEST_MAX_ACTIONS) {\n+\t\t\twpa_printf(MSG_ERROR,\n+\t\t\t\t   \"NAN Test action: Too many actions executed\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (!action->cb || !action->dev) {\n+\t\t\twpa_printf(MSG_ERROR,\n+\t\t\t\t   \"NAN Test action: Invalid action\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\twpa_printf(MSG_INFO, \"%s: ===> NAN Test action <===\",\n+\t\t\t   action->dev->name);\n+\t\tret = action->cb(action->dev, action->ctx);\n+\n+\t\t/*\n+\t\t * The action context should be freed by the callback function\n+\t\t * that understands the content of the context and can properly\n+\t\t * handle it.\n+\t\t */\n+\t\tos_free(action);\n+\n+\t\tif (ret) {\n+\t\t\twpa_printf(MSG_ERROR, \"NAN Test action: FAILED\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\twpa_printf(MSG_INFO, \"%s: Running actions done\", __func__);\n+\treturn 0;\n+}\n+\n+static int nan_test_start_cb(void *ctx, const struct nan_cluster_config *config)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * nan_test_stop_cb - Stop the NAN device.\n+ *\n+ * @ctx: Pointer to the &struct nan_device\n+ */\n+static void nan_test_stop_cb(void *ctx)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Done\", __func__, dev->name);\n+}\n+\n+\n+static int nan_test_nan_ndp_action(struct nan_device *dev, void *ctx)\n+{\n+\tstruct nan_ndp_params *params = (struct nan_ndp_params *)ctx;\n+\tint ret;\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: type=%u, peer_nmi=\" MACSTR,\n+\t\t   dev->name, __func__, params->type,\n+\t\t   MAC2STR(params->ndp_id.peer_nmi));\n+\n+\tret = nan_handle_ndp_setup(dev->nan, params);\n+\n+\tos_free(params);\n+\n+\treturn ret;\n+}\n+\n+\n+/*\n+ * nan_ndp_notify_action - Default NAN NDP notification handling\n+ *\n+ * @dev: NAN device\n+ * @ctx: Pointer to &struct nan_test_ndp_notify\n+ */\n+static int nan_ndp_notify_action(struct nan_device *dev, void *ctx)\n+{\n+\tstruct nan_test_ndp_notify *notify = (struct nan_test_ndp_notify *)ctx;\n+\tstruct nan_test_action *action;\n+\tint ret;\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: type=%u, peer_nmi=\" MACSTR,\n+\t\t   dev->name, __func__,\n+\t\t   notify->type, MAC2STR(notify->ndp_id.peer_nmi));\n+\n+\tret = -1;\n+\tif (notify->type == NAN_TEST_NDP_NOTIFY_REQUEST) {\n+\t\tstruct nan_ndp_params *params;\n+\t\tstruct nan_device *curd;\n+\t\tu8 found = 0;\n+\n+\t\tdl_list_for_each(curd, &dev->global->devs, struct nan_device,\n+\t\t\t\t list) {\n+\t\t\tif (os_memcmp(curd->nmi, notify->ndp_id.peer_nmi,\n+\t\t\t\t      ETH_ALEN) == 0) {\n+\t\t\t\tfound = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!found) {\n+\t\t\twpa_printf(MSG_ERROR, \"Peer device not found\");\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tparams = os_zalloc(sizeof(struct nan_ndp_params));\n+\t\tif (!params) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tparams->type = NAN_NDP_ACTION_RESP;\n+\t\tos_memcpy(params->ndp_id.peer_nmi, notify->ndp_id.peer_nmi,\n+\t\t\t  ETH_ALEN);\n+\t\tos_memcpy(params->ndp_id.init_ndi, notify->ndp_id.init_ndi,\n+\t\t\t  ETH_ALEN);\n+\t\tparams->ndp_id.id = notify->ndp_id.id;\n+\t\tparams->qos.min_slots = NAN_TEST_MIN_SLOTS;\n+\t\tparams->qos.max_latency = NAN_TEST_MAX_LATENCY;\n+\n+\t\tif (dev->conf->ndp_confs[dev->n_ndps].accept_request) {\n+\t\t\twpa_printf(MSG_INFO, \"%s: Accepting request\",\n+\t\t\t\t   dev->name);\n+\n+\t\t\tos_memcpy(params->u.resp.resp_ndi, pub_ndi, ETH_ALEN);\n+\t\t\tparams->u.resp.status = NAN_NDP_STATUS_ACCEPTED;\n+\t\t\tdev->conf->schedule_cb(&params->sched);\n+\t\t\tparams->sched.elems = dev->global->elems;\n+\t\t\tparams->sched_valid = 1;\n+\t\t} else {\n+\t\t\twpa_printf(MSG_INFO, \"%s: Rejecting request\",\n+\t\t\t\t   dev->name);\n+\n+\t\t\tparams->u.resp.status = NAN_NDP_STATUS_REJECTED;\n+\t\t\tparams->u.resp.reason_code =\n+\t\t\t\tdev->conf->ndp_confs[dev->n_ndps].reason;\n+\t\t}\n+\n+\t\taction = nan_test_add_action(dev->global, dev,\n+\t\t\t\t\t     nan_test_nan_ndp_action,\n+\t\t\t\t\t     params);\n+\t\tif (action)\n+\t\t\tret = 0;\n+\t} else if (notify->type == NAN_TEST_NDP_NOTIFY_RESPONSE) {\n+\t\tstruct nan_ndp_params *params;\n+\n+\t\tparams = os_zalloc(sizeof(struct nan_ndp_params));\n+\t\tif (!params) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tparams->type = NAN_NDP_ACTION_CONF;\n+\t\tos_memcpy(params->ndp_id.peer_nmi, notify->ndp_id.peer_nmi,\n+\t\t\t  ETH_ALEN);\n+\t\tos_memcpy(params->ndp_id.init_ndi, notify->ndp_id.init_ndi,\n+\t\t\t  ETH_ALEN);\n+\t\tparams->ndp_id.id = notify->ndp_id.id;\n+\n+\t\tparams->qos.min_slots = NAN_TEST_MIN_SLOTS;\n+\t\tparams->qos.max_latency = NAN_TEST_MAX_LATENCY;\n+\n+\t\tif (dev->conf->ndp_confs[dev->n_ndps].accept_request) {\n+\t\t\twpa_printf(MSG_INFO, \"%s: Accepting response\",\n+\t\t\t\t   dev->name);\n+\n+\t\t\tos_memcpy(params->u.resp.resp_ndi, sub_ndi, ETH_ALEN);\n+\t\t\tparams->u.resp.status = NAN_NDP_STATUS_ACCEPTED;\n+\n+\t\t\tif (!dev->conf->schedule_conf_cb) {\n+\t\t\t\twpa_printf(MSG_ERROR,\n+\t\t\t\t\t   \"%s: No schedule conf cb defined\",\n+\t\t\t\t\t   dev->name);\n+\t\t\t\tos_free(params);\n+\t\t\t\tret = -1;\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\n+\t\t\tdev->conf->schedule_conf_cb(&params->sched);\n+\t\t\tparams->sched.elems = dev->global->elems;\n+\t\t\tparams->sched_valid = 1;\n+\n+\t\t} else {\n+\t\t\twpa_printf(MSG_INFO, \"%s: Rejecting response\",\n+\t\t\t\t   dev->name);\n+\n+\t\t\tparams->u.resp.status = NAN_NDP_STATUS_REJECTED;\n+\t\t\tparams->u.resp.reason_code =\n+\t\t\t\tdev->conf->ndp_confs[dev->n_ndps].reason;\n+\t\t}\n+\n+\t\taction = nan_test_add_action(dev->global, dev,\n+\t\t\t\t\t     nan_test_nan_ndp_action,\n+\t\t\t\t\t     params);\n+\t\tif (action)\n+\t\t\tret = 0;\n+\t} else if (notify->type ==\n+\t\t   dev->conf->ndp_confs[dev->n_ndps].expected_result) {\n+\t\tret = 0;\n+\t\tif (notify->type == NAN_TEST_NDP_NOTIFY_CONNECTED) {\n+\t\t\tif (dev->conf->ndp_confs[dev->n_ndps].term_once_connected) {\n+\t\t\t\tstruct nan_ndp_params *params;\n+\n+\t\t\t\twpa_printf(MSG_INFO,\n+\t\t\t\t\t   \"%s: Connected successfully. Now term\",\n+\t\t\t\t\t   dev->name);\n+\n+\t\t\t\tparams = os_zalloc(sizeof(*params));\n+\t\t\t\tif (!params) {\n+\t\t\t\t\tret = -1;\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n+\n+\t\t\t\tparams->type = NAN_NDP_ACTION_TERM;\n+\t\t\t\tos_memcpy(params->ndp_id.peer_nmi,\n+\t\t\t\t\t  notify->ndp_id.peer_nmi,\n+\t\t\t\t\t  ETH_ALEN);\n+\t\t\t\tos_memcpy(params->ndp_id.init_ndi,\n+\t\t\t\t\t  notify->ndp_id.init_ndi,\n+\t\t\t\t\t  ETH_ALEN);\n+\t\t\t\tparams->ndp_id.id = notify->ndp_id.id;\n+\n+\t\t\t\taction = nan_test_add_action(dev->global, dev,\n+\t\t\t\t\t\t\t     nan_test_nan_ndp_action,\n+\t\t\t\t\t\t\t     params);\n+\t\t\t\tif (action)\n+\t\t\t\t\tret = 0;\n+\t\t\t}\n+\t\t}\n+\t} else if (notify->type == NAN_TEST_NDP_NOTIFY_DISCONNECTED &&\n+\t\t   dev->connected_notify_received) {\n+\t\twpa_printf(MSG_INFO,\n+\t\t\t   \"%s: Disconnected after connected as expected. Test case done\",\n+\t\t\t   dev->name);\n+\t\tret = 0;\n+\t} else {\n+\t\twpa_printf(MSG_ERROR,\n+\t\t\t   \"%s: Unexpected notify: type=%u expected=%u\",\n+\t\t\t   dev->name, notify->type,\n+\t\t\t   dev->conf->ndp_confs[dev->n_ndps].expected_result);\n+\t\tret = -1;\n+\t}\n+\n+out:\n+\tos_free((void *)notify->ssi);\n+\tos_free(notify);\n+\treturn ret;\n+}\n+\n+\n+static void nan_test_ndp_action(struct nan_device *dev, enum\n+\t\t\t\tnan_test_ndp_notify_type type,\n+\t\t\t\tstruct nan_ndp_id *ndp_id,\n+\t\t\t\tu8 publish_inst_id,\n+\t\t\t\tconst u8 *ssi, size_t ssi_len,\n+\t\t\t\tenum nan_cipher_suite_id csid,\n+\t\t\t\tconst u8 *pmkid)\n+{\n+\tstruct nan_test_ndp_notify *notify;\n+\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Enter: type=%u\",\n+\t\t   dev->name, __func__, type);\n+\n+\tnotify = os_zalloc(sizeof(struct nan_test_ndp_notify));\n+\tif (!notify) {\n+\t\twpa_printf(MSG_ERROR,\n+\t\t\t   \"Failed allocation: nan_test_ndp_notify\");\n+\t\treturn;\n+\t}\n+\n+\tnotify->type = type;\n+\tos_memcpy(&notify->ndp_id, ndp_id, sizeof(notify->ndp_id));\n+\n+\tif (ssi && ssi_len) {\n+\t\tnotify->ssi = os_memdup(ssi, ssi_len);\n+\t\tif (!notify->ssi) {\n+\t\t\twpa_printf(MSG_ERROR, \"Failed allocation: ssi\");\n+\t\t\tos_free(notify);\n+\t\t\treturn;\n+\t\t}\n+\t\tnotify->ssi_len = ssi_len;\n+\t}\n+\n+\tif (nan_test_add_action(dev->global, dev, nan_ndp_notify_action,\n+\t\t\t\tnotify))\n+\t\treturn;\n+\n+\tos_free((void *)notify->ssi);\n+\tos_free(notify);\n+}\n+\n+\n+/*\n+ * nan_test_ndp_action_notfi_cb - Callback for NDP request\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @params: NDP action notification parameters\n+ *\n+ * The handling of the event is done asynchronously through the NAN test actions\n+ * processing.\n+ */\n+static void nan_test_ndp_action_notfi_cb(void *ctx, struct\n+\t\t\t\t\t nan_ndp_action_notif_params *params)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\tenum nan_test_ndp_notify_type type;\n+\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\tif (params->is_request)\n+\t\ttype = NAN_TEST_NDP_NOTIFY_REQUEST;\n+\telse\n+\t\ttype = NAN_TEST_NDP_NOTIFY_RESPONSE;\n+\n+\tnan_test_ndp_action(dev, type, &params->ndp_id,\n+\t\t\t    params->publish_inst_id, params->ssi,\n+\t\t\t    params->ssi_len,\n+\t\t\t    params->csid, params->pmkid);\n+}\n+\n+\n+/*\n+ * nan_test_ndp_connected_cb - Callback for NDP connected\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @params: NDP action notification parameters\n+ *\n+ * The handling of the event is done asynchronously through the NAN test actions\n+ * processing.\n+ */\n+static void nan_test_ndp_connected_cb(void *ctx,\n+\t\t\t\t      struct nan_ndp_connection_params *params)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\tstruct nan_peer_schedule sched;\n+\tstruct nan_peer_potential_avail pot;\n+\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\twpa_printf(MSG_INFO,\n+\t\t   \"%s: %s: Enter. local_ndi=\" MACSTR \" peer_ndi=\" MACSTR,\n+\t\t   dev->name, __func__,\n+\t\t   MAC2STR(params->local_ndi), MAC2STR(params->peer_ndi));\n+\n+\tnan_peer_get_schedule_info(dev->nan, params->ndp_id.peer_nmi,\n+\t\t\t\t   &sched);\n+\tnan_peer_get_pot_avail(dev->nan, params->ndp_id.peer_nmi,\n+\t\t\t       &pot);\n+\n+\tnan_test_ndp_action(dev, NAN_TEST_NDP_NOTIFY_CONNECTED,\n+\t\t\t    &params->ndp_id, 0,\n+\t\t\t    params->ssi, params->ssi_len,\n+\t\t\t    NAN_CS_NONE, NULL);\n+\n+\tdev->connected_notify_received = true;\n+}\n+\n+\n+/*\n+ * nan_test_ndp_disconnected_cb - Callback for NDP disconnected\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @ndp_id: NDP identifier\n+ * @local_ndi: Local NDI address\n+ * @peer_ndi: Peer NDI address\n+ * @reason: Reason for disconnection\n+ *\n+ * The handling of the event is done asynchronously through the NAN test actions\n+ * processing.\n+ */\n+static void nan_test_ndp_disconnected_cb(void *ctx, struct nan_ndp_id *ndp_id,\n+\t\t\t\t\t const u8 *local_ndi,\n+\t\t\t\t\t const u8 *peer_ndi,\n+\t\t\t\t\t enum nan_reason reason)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\n+\tDEV_NOT_INIT_ERR_VOID(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Enter\", dev->name, __func__);\n+\n+\tnan_test_ndp_action(dev, NAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+\t\t\t    ndp_id, 0, NULL, 0, NAN_CS_NONE, NULL);\n+\n+\tdev->disconnected_notify_received = true;\n+}\n+\n+\n+/*\n+ * nan_test_send_naf_cb_action - NAN test action to send a NAN to a device\n+ *\n+ * @dev: NAN device\n+ * @ctx: Pointer to a buffer holding the NAF to be sent\n+ */\n+static int nan_test_send_naf_cb_action(struct nan_device *dev, void *ctx)\n+{\n+\tstruct wpabuf *data = (struct wpabuf *)ctx;\n+\tint ret;\n+\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Enter\", dev->name, __func__);\n+\twpa_hexdump(MSG_DEBUG, \"NAN Test: NAF:\", wpabuf_head(data),\n+\t\t    wpabuf_len(data));\n+\n+\tret = nan_action_rx(dev->nan, wpabuf_head(data), wpabuf_len(data));\n+\twpabuf_free(data);\n+\treturn ret;\n+}\n+\n+/*\n+ * nan_test_tx_status_action - NAN test action to send Tx status to a device\n+ *\n+ * @dev: NAN device\n+ * @ctx: Pointer to &struct nan_test_tx_status_action\n+ */\n+static int nan_test_tx_status_action(struct nan_device *dev, void *ctx)\n+{\n+\tstruct nan_test_tx_status_action *tx_status =\n+\t\t(struct nan_test_tx_status_action *)ctx;\n+\tint ret;\n+\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: enter\", dev->name, __func__);\n+\n+\tret = nan_tx_status(dev->nan, tx_status->dst,\n+\t\t\t    wpabuf_head(tx_status->data),\n+\t\t\t    wpabuf_len(tx_status->data), tx_status->acked);\n+\n+\twpabuf_free((struct wpabuf *)tx_status->data);\n+\tos_free(tx_status);\n+\treturn ret;\n+}\n+\n+/*\n+ * nan_test_send_naf_cb - NAN send NAF callback function\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @dst: Destination NAN Management Interface address\n+ * @src: Source NAN Management Interface address\n+ * @cluster_id: NAN Cluster ID\n+ *\n+ * The callback builds the management frame and creates the following NAN test\n+ * actions:\n+ * - NAN test tx status action: to be sent to the transmitting device\n+ * - NAN test send NAF action: to be sent to the destination device.\n+ */\n+static int nan_test_send_naf_cb(void *ctx, const u8 *dst, const u8 *src,\n+\t\t\t\tconst u8 *cluster_id, struct wpabuf *buf)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\tstruct nan_device *curd;\n+\tstruct ieee80211_hdr *hdr;\n+\tstruct wpabuf *data = NULL;\n+\tstruct nan_test_tx_status_action *tx_status = NULL;\n+\tstruct nan_test_action *dev_action, *cur_action;\n+\tbool found = false;\n+\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Enter \" MACSTR, __func__, dev->name,\n+\t\t   MAC2STR(dst));\n+\n+\tdl_list_for_each(curd, &dev->global->devs, struct nan_device, list) {\n+\t\tif (os_memcmp(curd->nmi, dst, ETH_ALEN) == 0) {\n+\t\t\tfound = true;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (!found) {\n+\t\twpa_printf(MSG_ERROR, \"%s: Destination device not found\",\n+\t\t\t   __func__);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Prepare action to send the frame to the peer */\n+\tdata = wpabuf_alloc(sizeof(struct ieee80211_hdr) + wpabuf_len(buf));\n+\tif (!data) {\n+\t\twpa_printf(MSG_ERROR, \"%s: Failed to allocate NAF\", __func__);\n+\t\treturn -1;\n+\t}\n+\n+\thdr = wpabuf_put(data, sizeof(struct ieee80211_hdr));\n+\thdr->frame_control =\n+\t\tIEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);\n+\n+\tif (dst)\n+\t\tos_memcpy(hdr->addr1, dst, ETH_ALEN);\n+\tif (!src)\n+\t\tos_memcpy(hdr->addr2, dev->nmi, ETH_ALEN);\n+\telse\n+\t\tos_memcpy(hdr->addr2, src, ETH_ALEN);\n+\tif (cluster_id)\n+\t\tos_memcpy(hdr->addr3, cluster_id, ETH_ALEN);\n+\n+\twpabuf_put_data(data, wpabuf_head(buf), wpabuf_len(buf));\n+\n+\t/* Prepare action to send Tx status */\n+\ttx_status = os_malloc(sizeof(struct nan_test_tx_status_action));\n+\tif (!tx_status) {\n+\t\twpa_printf(MSG_ERROR, \"%s: Failed to allocate Tx status\",\n+\t\t\t   __func__);\n+\t\tgoto fail;\n+\t}\n+\n+\ttx_status->data = wpabuf_dup(data);\n+\tif (!tx_status->data) {\n+\t\twpa_printf(MSG_ERROR, \"%s: Failed to allocate Tx status data\",\n+\t\t\t   __func__);\n+\t\tgoto fail;\n+\t}\n+\n+\tos_memcpy(tx_status->dst, dst, ETH_ALEN);\n+\ttx_status->acked = 1;\n+\n+\t/* First send the TX status */\n+\tdev_action = nan_test_add_action(dev->global, dev,\n+\t\t\t\t\t nan_test_tx_status_action,\n+\t\t\t\t\t tx_status);\n+\tif (!dev_action)\n+\t\tgoto fail;\n+\n+\t/* And then deliver the frame */\n+\tcur_action = nan_test_add_action(curd->global, curd,\n+\t\t\t\t\t nan_test_send_naf_cb_action,\n+\t\t\t\t\t data);\n+\tif (!cur_action)\n+\t\tgoto fail;\n+\n+\treturn 0;\n+fail:\n+\twpabuf_free(data);\n+\tif (tx_status)\n+\t\twpabuf_free((struct wpabuf *)tx_status->data);\n+\n+\tos_free(tx_status);\n+\n+\treturn -1;\n+}\n+\n+\n+/*\n+ * nan_test_get_chans_cb - Get NAN supported channels callback\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @map_id: Channel map identifier\n+ * @chans: Pointer to &struct nan_channels to be filled with supported channels\n+ */\n+static int nan_test_get_chans_cb(void *ctx, u8 map_id,\n+\t\t\t\t struct nan_channels *chans)\n+{\n+\tstruct nan_device *dev = (struct nan_device *)ctx;\n+\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\twpa_printf(MSG_INFO, \"%s: %s: Enter\", dev->name, __func__);\n+\n+\treturn dev->conf->get_chans_cb(chans);\n+}\n+\n+\n+/*\n+ * nan_test_is_valid_publish_id_cb - Check if the publish instance ID is valid\n+ *\n+ * @ctx: Pointer to &struct nan_device\n+ * @instance_id: Publish instance ID\n+ * @service_id: Buffer to be filled with the service ID\n+ * Returns true if the instance ID is valid, false otherwise\n+ */\n+static bool nan_test_is_valid_publish_id_cb(void *ctx, u8 instance_id,\n+\t\t\t\t\t    u8 *service_id)\n+{\n+\tif (instance_id != NAN_TEST_PUBLISH_INST_ID)\n+\t\treturn false;\n+\n+\tos_memset(service_id, 0xaa, NAN_SERVICE_ID_LEN);\n+\treturn true;\n+}\n+\n+\n+/*\n+ * nan_test_dev_init - Initialize a test device instance\n+ *\n+ * @dev: the instance of the device to initialize\n+ */\n+static int nan_test_dev_init(struct nan_device *dev)\n+{\n+\tstruct nan_config nan;\n+\n+\tos_memset(&nan, 0, sizeof(nan));\n+\tnan.cb_ctx = dev;\n+\n+\tnan.start = nan_test_start_cb;\n+\tnan.stop = nan_test_stop_cb;\n+\tnan.ndp_action_notif = nan_test_ndp_action_notfi_cb;\n+\tnan.ndp_connected = nan_test_ndp_connected_cb;\n+\tnan.ndp_disconnected = nan_test_ndp_disconnected_cb;\n+\tnan.send_naf = nan_test_send_naf_cb;\n+\tnan.get_chans = nan_test_get_chans_cb;\n+\tnan.is_valid_publish_id = nan_test_is_valid_publish_id_cb;\n+\n+\t/* Awake on every DW on 2 GHz and 5 GHz */\n+\tnan.dev_capa.cdw_info = 0x9;\n+\tnan.dev_capa.supported_bands = NAN_DEV_CAPA_SBAND_2G |\n+\t\tNAN_DEV_CAPA_SBAND_5G |\n+\t\tNAN_DEV_CAPA_SBAND_6G;\n+\n+\tnan.dev_capa.op_mode = NAN_DEV_CAPA_OP_MODE_PHY_MODE;\n+\tnan.dev_capa.n_antennas = 0x22;\n+\tnan.dev_capa.channel_switch_time = 10;\n+\tnan.dev_capa.capa = 0;\n+\n+\tnan.dev_capa_ext_reg_info = 0;\n+\tnan.dev_capa_ext_pairing_npk_caching =\n+\t\tNAN_DEV_CAPA_EXT_INFO_1_PAIRING_SETUP |\n+\t\tNAN_DEV_CAPA_EXT_INFO_1_NPK_NIK_CACHING;\n+\n+\tdev->nan = nan_init(&nan);\n+\tif (!dev->nan) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Failed to init\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * nan_test_start_dev - Start a NAN test device\n+ *\n+ * @global: NAN test global data structure\n+ * @name: Name of the device\n+ * @nmi: NAN Management interface address\n+ * @cconf: NAN cluster configuration\n+ * @dconf: Test device configuration\n+ */\n+static struct nan_device *\n+nan_test_start_dev(struct nan_test_global *global,\n+\t\t   const char *name, const u8 *nmi,\n+\t\t   struct nan_cluster_config *conf,\n+\t\t   struct nan_test_dev_conf *dconf)\n+{\n+\tstruct nan_device *dev;\n+\tint ret;\n+\n+\tdev = os_zalloc(sizeof(struct nan_device));\n+\tif (!dev)\n+\t\treturn NULL;\n+\n+\tos_memcpy(dev->name, name, os_strlen(name));\n+\tos_memcpy(dev->nmi, nmi, sizeof(dev->nmi));\n+\tdl_list_init(&dev->list);\n+\tdev->global = global;\n+\n+\tif (dconf->pot_avail_len) {\n+\t\tdev->pot_avail = os_memdup(dconf->pot_avail,\n+\t\t\t\t\t   dconf->pot_avail_len);\n+\t\tif (!dev->pot_avail)\n+\t\t\tgoto fail;\n+\t\tdev->pot_avail_len = dconf->pot_avail_len;\n+\t}\n+\n+\tret = nan_test_dev_init(dev);\n+\tif (ret)\n+\t\tgoto fail;\n+\n+\tdev->conf = dconf;\n+\tret = nan_start(dev->nan, conf);\n+\tif (ret)\n+\t\tgoto fail;\n+\n+\tdl_list_add(&global->devs, &dev->list);\n+\treturn dev;\n+fail:\n+\tos_free(dev->pot_avail);\n+\tnan_test_dev_deinit(dev);\n+\tos_free(dev);\n+\treturn NULL;\n+}\n+\n+\n+/*\n+ * nan_test_setup_devices - Setup the test devices\n+ *\n+ * @global: NAN test global data structure\n+ * @pub_conf: Publisher test configuration\n+ * @sub_conf: Subscriber test configuration\n+ */\n+static struct nan_device *\n+nan_test_setup_devices(struct nan_test_global *global,\n+\t\t       struct nan_test_dev_conf *pub_conf,\n+\t\t       struct nan_test_dev_conf *sub_conf)\n+{\n+\tstruct nan_cluster_config cconf = {\n+\t\t.master_pref = 2,\n+\t\t.dual_band = 1,\n+\t};\n+\tconst u8 pot_avail[] = {\n+\t\t0x12, 0x0c, 0x00, 0x01, 0x20, 0x00, 0x07, 0x00,\n+\t\t0x1a, 0x00, 0x11, 0x51, 0xff, 0x07, 0x00,\n+\t};\n+\n+\tstruct nan_device *pub, *sub;\n+\n+\twpa_printf(MSG_INFO, \"%s: Enter\\n\", __func__);\n+\n+\tpub = nan_test_start_dev(global, \"publisher\", pub_nmi, &cconf,\n+\t\t\t\t pub_conf);\n+\tif (!pub)\n+\t\tgoto fail;\n+\n+\tsub = nan_test_start_dev(global, \"subscriber\", sub_nmi, &cconf,\n+\t\t\t\t sub_conf);\n+\tif (!sub)\n+\t\tgoto fail;\n+\n+\tnan_add_peer(pub->nan, sub_nmi, pot_avail, sizeof(pot_avail));\n+\tnan_add_peer(sub->nan, pub_nmi, pot_avail, sizeof(pot_avail));\n+\n+\twpa_printf(MSG_INFO, \"\\n%s: Done\\n\", __func__);\n+\treturn sub;\n+fail:\n+\twpa_printf(MSG_INFO, \"\\n%s: Fail\\n\", __func__);\n+\treturn NULL;\n+}\n+\n+\n+static int nan_test_ndp_request(struct nan_device *sub)\n+{\n+\tstruct nan_ndp_params *params;\n+\tstruct nan_test_action *action;\n+\n+\tDEV_NOT_INIT_ERR(sub);\n+\n+\tparams = os_zalloc(sizeof(struct nan_ndp_params));\n+\tif (!params) {\n+\t\twpa_printf(MSG_ERROR, \"Failed allocation: nan_ndp_params\");\n+\t\treturn -1;\n+\t}\n+\n+\tparams->type = NAN_NDP_ACTION_REQ;\n+\tos_memcpy(params->ndp_id.peer_nmi, pub_nmi, ETH_ALEN);\n+\tos_memcpy(params->ndp_id.init_ndi, sub_ndi, ETH_ALEN);\n+\tparams->ndp_id.id = ++sub->counter;\n+\tparams->qos.min_slots = NAN_TEST_MIN_SLOTS;\n+\tparams->qos.max_latency = NAN_TEST_MAX_LATENCY;\n+\n+\t/* Use the device specific schedule callback */\n+\tsub->conf->schedule_cb(&params->sched);\n+\tparams->sched_valid = 1;\n+\tparams->sched.elems = sub->global->elems;\n+\n+\tparams->u.req.publish_inst_id = NAN_TEST_PUBLISH_INST_ID;\n+\tos_memset(params->u.req.service_id, 0xaa, NAN_SERVICE_ID_LEN);\n+\n+\taction = nan_test_add_action(sub->global, sub, nan_test_nan_ndp_action,\n+\t\t\t\t     params);\n+\tif (action)\n+\t\treturn 0;\n+\n+\twpa_printf(MSG_ERROR, \"Failed adding NDP request action\");\n+\tos_free(params);\n+\n+\treturn -1;\n+}\n+\n+\n+/*\n+ * nan_test_ndp_setup - test NDP setup\n+ *\n+ * @global: NAN test global data structure\n+ * @pub_conf: Publisher test configuration\n+ * @sub_conf: Subscriber test configuration\n+ *\n+ * Create the test devices, perform the basic publish/subscribe/match to allow\n+ * NDP establishment and trigger an NDP request flow based on the actions\n+ * mechanism.\n+ */\n+static struct nan_device *nan_test_ndp_setup(struct nan_test_global *global,\n+\t\t\t\t\t     struct nan_test_dev_conf *pub_conf,\n+\t\t\t\t\t     struct nan_test_dev_conf *sub_conf)\n+{\n+\tif (pub_conf->n_ndps != sub_conf->n_ndps || !pub_conf->n_ndps ||\n+\t    pub_conf->n_ndps >= NAN_MAX_NUM_NDPS) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN Test: Publisher and Subscriber n_ndps mismatch or invalid\");\n+\t\treturn NULL;\n+\t}\n+\n+\treturn nan_test_setup_devices(global, pub_conf, sub_conf);\n+}\n+\n+\n+static int nan_test_verify_expected_result(struct nan_device *dev)\n+{\n+\tDEV_NOT_INIT_ERR(dev);\n+\n+\tif (dev->conf->ndp_confs[dev->n_ndps].expected_result ==\n+\t    NAN_TEST_NDP_NOTIFY_CONNECTED &&\n+\t    !dev->connected_notify_received) {\n+\t\twpa_printf(MSG_ERROR,\n+\t\t\t   \"%s: Expected connected notify not received\",\n+\t\t\t   dev->name);\n+\t\treturn -1;\n+\t} else if (dev->conf->ndp_confs[dev->n_ndps].expected_result ==\n+\t\t   NAN_TEST_NDP_NOTIFY_DISCONNECTED &&\n+\t\t   !dev->disconnected_notify_received) {\n+\t\twpa_printf(MSG_ERROR,\n+\t\t\t   \"%s: Expected disconnected notify not received\",\n+\t\t\t   dev->name);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static int nan_test_iteration_done(struct nan_test_global *global)\n+{\n+\tstruct nan_device *dev;\n+\tint ret;\n+\n+\tdl_list_for_each(dev, &global->devs, struct nan_device, list) {\n+\t\tret = nan_test_verify_expected_result(dev);\n+\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tdev->connected_notify_received = false;\n+\t\tdev->disconnected_notify_received = false;\n+\t\tdev->n_ndps++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * nan_test_run - Run the NAN tests.\n+ *\n+ * Iterates over all tests cases and for each test case initializes the global\n+ * context, creates the NAN devices and perform the test case.\n+ */\n+static int nan_test_run(void)\n+{\n+\tstruct nan_test_global global;\n+\tstruct nan_test_case *curr_tc;\n+\tbool all_failed = false;\n+\n+\twhile ((curr_tc = nan_test_case_get_next()) != NULL) {\n+\t\tstruct nan_device *sub;\n+\t\tbool failed = false;\n+\t\tsize_t i;\n+\n+\t\twpa_printf(MSG_INFO,\n+\t\t\t   \"\\n======> NAN TEST CASE: %s <======\\n\",\n+\t\t\t   curr_tc->name);\n+\n+\t\tnan_test_global_init(&global);\n+\t\tsub = nan_test_ndp_setup(&global,\n+\t\t\t\t\t &curr_tc->pub_conf,\n+\t\t\t\t\t &curr_tc->sub_conf);\n+\t\tif (!sub) {\n+\t\t\twpa_printf(MSG_ERROR,\n+\t\t\t\t   \"NAN Test: Failed to setup devices\");\n+\t\t\tnan_test_global_deinit(&global);\n+\t\t\tfailed = true;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < sub->conf->n_ndps; i++) {\n+\t\t\tint ret = nan_test_ndp_request(sub);\n+\n+\t\t\tif (!ret)\n+\t\t\t\tret = nan_test_run_actions(&global);\n+\n+\t\t\tif (!ret)\n+\t\t\t\tret = nan_test_iteration_done(&global);\n+\n+\t\t\twpa_printf(MSG_INFO,\n+\t\t\t\t   \"\\n======> NAN TEST CASE: %s: iter=%zu: result=%s <======\\n\",\n+\t\t\t\t   curr_tc->name, i, ret ? \"FAILED\" : \"SUCCESS\");\n+\n+\t\t\tif (ret) {\n+\t\t\t\tfailed = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\twpa_printf(MSG_INFO,\n+\t\t\t   \"\\n======> NAN TEST CASE: %s: Done. Result=%s <======\\n\",\n+\t\t\t   curr_tc->name, failed ? \"FAILED\" : \"SUCCESS\");\n+\n+\t\tall_failed |= failed;\n+\n+\t\tnan_test_global_deinit(&global);\n+\t}\n+\n+\treturn all_failed ? -1 : 0;\n+}\n+\n+\n+int nan_module_tests(void)\n+{\n+\treturn nan_test_run();\n+}\ndiff --git a/src/nan/nan_module_tests.h b/src/nan/nan_module_tests.h\nnew file mode 100644\nindex 0000000000..f50eb76953\n--- /dev/null\n+++ b/src/nan/nan_module_tests.h\n@@ -0,0 +1,129 @@\n+/*\n+ * NAN NDP/NDL state machine testing definitions\n+ * Copyright (C) 2025 Intel Corporation\n+ *\n+ * This software may be distributed under the terms of the BSD license.\n+ * See README for more details.\n+ */\n+\n+#include \"utils/includes.h\"\n+#include \"utils/list.h\"\n+#include \"utils/os.h\"\n+#include \"utils/common.h\"\n+#include \"utils/eloop.h\"\n+#include \"common/ieee802_11_defs.h\"\n+#include \"drivers/driver.h\"\n+#include \"nan_i.h\"\n+\n+#define NAN_TEST_NAME_MAX     32\n+\n+/*\n+ * enum nan_test_ndp_notify_type - NDP notification\n+ *\n+ * NAN_TEST_NDP_NOTIFY_INVALID: Invalid.\n+ * NAN_TEST_NDP_NOTIFY_REQUEST: NDP request\n+ * NAN_TEST_NDP_NOTIFY_RESPONSE: NDP response\n+ * NAN_TEST_NDP_NOTIFY_CONNECTED: NDP connected\n+ * NAN_TEST_NDP_NOTIFY_DISCONNECTED: NDP disconnected.\n+ */\n+enum nan_test_ndp_notify_type {\n+\tNAN_TEST_NDP_NOTIFY_INVALID = 0,\n+\tNAN_TEST_NDP_NOTIFY_REQUEST,\n+\tNAN_TEST_NDP_NOTIFY_RESPONSE,\n+\tNAN_TEST_NDP_NOTIFY_CONNECTED,\n+\tNAN_TEST_NDP_NOTIFY_DISCONNECTED,\n+};\n+\n+#define NAN_TEST_MAX_POT_AVAIL 256\n+#define NAN_MAX_NUM_NDPS       8\n+\n+/*\n+ * nan_test_dev_conf - NAN test device configuration\n+ *\n+ * @schedule_cb: Callback to configure different schedule handling policies\n+ *     for a device for initial request and response.\n+ * @schedule_conf_cb: Callback to configure different schedule handling\n+ *     policies for a device for confirmation.\n+ * @get_chans_cb: Callback to configure different channels for potential\n+ *     availability.\n+ * @pot_avail: Device potential availability\n+ * @pot_avail_len: Length of the device potential availability\n+ * @n_ndps: Number of NDP configurations (to support scenarios that involve\n+ *      establishing multiple NDPs in a single test case).\n+ * @ndp_confs: Array of NDP configurations.\n+ * @accept_request: For publisher device, indicates whether to accept an NDP\n+ *     request or reject it. For subscriber device, indicates whether to accept\n+ *     an NDP response or reject it.\n+ * @term_once_connected: Terminate once connected.\n+ * @expected_result: Expected NDP establishment result\n+ * @reason: For publisher device, indicates the reject reason\n+ */\n+struct nan_test_dev_conf {\n+\tint (*schedule_cb)(struct nan_schedule *sched);\n+\tint (*schedule_conf_cb)(struct nan_schedule *sched);\n+\tint (*get_chans_cb)(struct nan_channels *chans);\n+\n+\tu8 pot_avail[NAN_TEST_MAX_POT_AVAIL];\n+\tsize_t pot_avail_len;\n+\n+\tsize_t n_ndps;\n+\tstruct ndp_conf {\n+\t\tbool accept_request;\n+\t\tbool term_once_connected;\n+\t\tenum nan_test_ndp_notify_type expected_result;\n+\t\tu8 reason;\n+\t} ndp_confs[NAN_MAX_NUM_NDPS];\n+};\n+\n+/*\n+ * nan_device - Represents a NAN test device\n+ *\n+ * @list: Used for global devices list\n+ * @global: Pointer to NAN test global data structure\n+ * @name: Test device name\n+ * @nmi: Test device NMI\n+ * @counter: Device counter for NDP various purposes\n+ * @pot_avail: Device potential availability\n+ * @pot_avail_len: Length of the device potential availability\n+ * @nan: Pointer to NAN data structure\n+ * @conf: NAN test device configuration\n+ * @n_ndps: Number of NDPs established so far minus one\n+ * @connected_notify_received: Indicates whether a connected notification\n+ *     was received\n+ * @disconnected_notify_received: Indicates whether a disconnected notification\n+ *     was received\n+ */\n+struct nan_device {\n+\tstruct dl_list list;\n+\tstruct nan_test_global *global;\n+\n+\tu8 name[NAN_TEST_NAME_MAX];\n+\tu8 nmi[ETH_ALEN];\n+\tu32 counter;\n+\n+\tu8 *pot_avail;\n+\tsize_t pot_avail_len;\n+\n+\tstruct nan_data *nan;\n+\tstruct nan_test_dev_conf *conf;\n+\n+\tsize_t n_ndps;\n+\n+\tbool connected_notify_received;\n+\tbool disconnected_notify_received;\n+};\n+\n+/*\n+ * nan_test_case - Single NAN test configuration\n+ *\n+ * @name: Test name\n+ * @pub_conf: Publisher test configuration\n+ * @sub_conf: Subscriber test configuration\n+ */\n+struct nan_test_case {\n+\tconst char *name;\n+\tstruct nan_test_dev_conf pub_conf;\n+\tstruct nan_test_dev_conf sub_conf;\n+};\n+\n+struct nan_test_case *nan_test_case_get_next(void);\ndiff --git a/src/utils/module_tests.h b/src/utils/module_tests.h\nindex 3bfe4ad026..14f26a1398 100644\n--- a/src/utils/module_tests.h\n+++ b/src/utils/module_tests.h\n@@ -16,5 +16,6 @@ int utils_module_tests(void);\n int wps_module_tests(void);\n int common_module_tests(void);\n int crypto_module_tests(void);\n+int nan_module_tests(void);\n \n #endif /* MODULE_TESTS_H */\ndiff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile\nindex 283dd01d65..e318726487 100644\n--- a/wpa_supplicant/Makefile\n+++ b/wpa_supplicant/Makefile\n@@ -1947,6 +1947,10 @@ OBJS += ../src/crypto/crypto_module_tests.o\n ifdef CONFIG_WPS\n OBJS += ../src/wps/wps_module_tests.o\n endif\n+ifdef CONFIG_NAN\n+OBJS += ../src/nan/nan_module_tests.o\n+OBJS += ../src/nan/nan_module_test_cases.o\n+endif\n endif\n \n OBJS += ../src/drivers/driver_common.o\ndiff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c\nindex 9e7a57c4f1..b9140fba87 100644\n--- a/wpa_supplicant/wpas_module_tests.c\n+++ b/wpa_supplicant/wpas_module_tests.c\n@@ -113,5 +113,10 @@ int wpas_module_tests(void)\n \tif (crypto_module_tests() < 0)\n \t\tret = -1;\n \n+#ifdef CONFIG_NAN\n+\tif (nan_module_tests() < 0)\n+\t\tret = -1;\n+#endif /* CONFIG_NAN */\n+\n \treturn ret;\n }\n",
    "prefixes": [
        "55/58"
    ]
}