get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2198411,
    "url": "http://patchwork.ozlabs.org/api/1.0/patches/2198411/?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-13-andrei.otcheretianski@intel.com>",
    "date": "2026-02-19T20:24:28",
    "name": "[12/58] NAN: Add support for parsing NAN availability attribute",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "dd93b7ab6cba1e7f135d09560decef6aae83e557",
    "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-13-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/2198411/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=Cod25vmM;\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=KNnofB5q;\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 4fH4fP0KVPz1xxN\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 20 Feb 2026 07:26:37 +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 1vtAbD-0000000BwG8-3h49;\n\tThu, 19 Feb 2026 20:26:11 +0000",
            "from mgamail.intel.com ([198.175.65.10])\n\tby bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux))\n\tid 1vtAb8-0000000Bw7w-2ZTp\n\tfor hostap@lists.infradead.org;\n\tThu, 19 Feb 2026 20:26:08 +0000",
            "from orviesa004.jf.intel.com ([10.64.159.144])\n  by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 19 Feb 2026 12:26:06 -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:26:03 -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=t3erBB4e+a4QJ4Yas8wPm7lsRb5z/8rmM8IcsyezOFY=; b=Cod25vmM9oksN6\n\tmO4tuNhbXTe0Z/0B6vKdmJjy8hKHOGY9OmeDBOyfLIYxLG7DmjkTrpmbFFDsF5gkGpiVspwYs8r0Y\n\tw6ML4b6baPsulcyUpE7CEDjz0f0bl9KWgCf0JGC2pTn0pNjvXBTjHWdx7UIDmInU1dCVSzW/rHZ0F\n\tRT00OSDujNsUrcA2CzYGnWy4pYkmg7o9YAvCKJQWHOfNnN834daZ4MfxRTYxgD3wwQh/Iou01cxzW\n\tK+VmOMj+hrr06B5D7dbcRywvCQ/i+iLLpfipq9foJv9iqxwry+HzM5O9rne360hiS/hCTY4RhXi5P\n\tq1pNJzT9/KeB6GwR9POQ==;",
            "v=1; a=rsa-sha256; c=relaxed/simple;\n  d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n  t=1771532767; x=1803068767;\n  h=from:to:cc:subject:date:message-id:in-reply-to:\n   references:mime-version:content-transfer-encoding;\n  bh=IqojdlprITLykryin257kNBElls4PSmfTFqoWinH0Qg=;\n  b=KNnofB5q95idELdocsk7bBYBZSfzCE4CbYrTiYUxfFL0k1t2kn3JILox\n   498Qaz360P1+DJ/xEPhu4ZJ7V0V0XFvslJ5VjfSch5kwhPPDSPR5Nzdar\n   /E0D2jjf90+sMUU88fAQG1jlOdyHB3V6Y8ya1XSMWvuvAkdMsk2UiWxg9\n   35EkT/vIrqdJU0VWIbWO+lmMfEDp5yOqUv0LKP4z2wq8LkTOPtCqC8kzi\n   cDEGxAfI6dS/fdcVRaEwqiEvvhCq43It9egeRsj1ISIiNUiC38+eeAQdU\n   51zYGvXBcGykkH6H3BBeZZrMyr4ho7gzZnqWwxvn5ArF+Io3RKFDVESjq\n   g==;"
        ],
        "X-CSE-ConnectionGUID": [
            "9waH+bJLRxiZXuqKILH4pQ==",
            "pncLwR0mQqWxK2TUlye5qQ=="
        ],
        "X-CSE-MsgGUID": [
            "FhZrxbfgS6SmwS0tG9Rk2Q==",
            "NoZZ/S9iQiKbpS0dkzMvXQ=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6800,10657,11706\"; a=\"90039967\"",
            "E=Sophos;i=\"6.21,300,1763452800\";\n   d=\"scan'208\";a=\"90039967\"",
            "E=Sophos;i=\"6.21,300,1763452800\";\n   d=\"scan'208\";a=\"219153766\""
        ],
        "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 12/58] NAN: Add support for parsing NAN availability attribute",
        "Date": "Thu, 19 Feb 2026 22:24:28 +0200",
        "Message-ID": "<20260219202514.5781-13-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_122607_375667_0B3E4AD7 ",
        "X-CRM114-Status": "GOOD (  25.05  )",
        "X-Spam-Score": "-4.4 (----)",
        "X-Spam-Report": "Spam detection software,\n running on the system \"bombadil.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> Support parsing\n availability\n    attributes and store the result for the given peer. Signed-off-by: Ilan\n Peer\n    <ilan.peer@intel.com> --- src/nan/nan.c | 653\n ++++++++++++++++++++++++++++++++++++++++++++++++\n    src/nan/nan_i.h | 77 ++++++ 2 files changed, 730 insertions(+)\n Content analysis details:   (-4.4 points, 5.0 required)\n  pts rule name              description\n ---- ----------------------\n --------------------------------------------------\n -2.3 RCVD_IN_DNSWL_MED      RBL: Sender listed at https://www.dnswl.org/,\n                             medium trust\n                             [198.175.65.10 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.10 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.10 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.10 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_EF          Message has a valid DKIM or DK signature from\n                             envelope-from domain\n -0.1 DKIM_VALID             Message has at least one valid DKIM or DK\n signature\n  0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n not necessarily valid\n -1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n                             [score: 0.0000]\n -0.0 DKIMWL_WL_HIGH         DKIMwl.org - High trust sender",
        "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\nSupport parsing availability attributes and store the\nresult for the given peer.\n\nSigned-off-by: Ilan Peer <ilan.peer@intel.com>\n---\n src/nan/nan.c   | 653 ++++++++++++++++++++++++++++++++++++++++++++++++\n src/nan/nan_i.h |  77 ++++++\n 2 files changed, 730 insertions(+)",
    "diff": "diff --git a/src/nan/nan.c b/src/nan/nan.c\nindex 82d301c680..a88455ed2c 100644\n--- a/src/nan/nan.c\n+++ b/src/nan/nan.c\n@@ -38,6 +38,25 @@ struct nan_data * nan_init(const struct nan_config *cfg)\n }\n \n \n+static void nan_del_avail_entry(struct nan_avail_entry *entry)\n+{\n+\tos_free(entry->band_chan);\n+\tos_free(entry);\n+}\n+\n+\n+static void nan_peer_flush_avail(struct nan_peer_info *info)\n+{\n+\tstruct nan_avail_entry *cur, *next;\n+\n+\tdl_list_for_each_safe(cur, next, &info->avail_entries,\n+\t\t\t      struct nan_avail_entry, list) {\n+\t\tdl_list_del(&cur->list);\n+\t\tnan_del_avail_entry(cur);\n+\t}\n+}\n+\n+\n static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)\n {\n \tif (!peer)\n@@ -67,6 +86,7 @@ static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)\n \t}\n \n \tdl_list_del(&peer->list);\n+\tnan_peer_flush_avail(&peer->info);\n \tos_free(peer);\n }\n \n@@ -173,6 +193,638 @@ struct nan_peer * nan_get_peer(struct nan_data *nan, const u8 *addr)\n }\n \n \n+/*\n+ * nan_parse_tbm - Parse NAN Time Bitmap attribute\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @tbm: On return would hold the parsed time bitmap\n+ * @buf: Buffer holding the time bitmap\n+ * @buf_len: Length of &buf\n+ * Return 0 on success; otherwise -1\n+ */\n+static int nan_parse_tbm(struct nan_data *nan, struct nan_time_bitmap *tbm,\n+\t\t\t const u8 *buf, u16 buf_len)\n+{\n+\tu32 period;\n+\tu16 ctrl;\n+\tstruct nan_tbm *bm;\n+\tu8 duration_bit;\n+\n+\tif (buf_len < sizeof(*bm)) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Too short time bitmap length (%u)\",\n+\t\t\t   buf_len);\n+\t\treturn -1;\n+\t}\n+\n+\tbm = (void *)buf;\n+\tif (!bm->len || bm->len + sizeof(*bm) > buf_len) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Invalid tbm length (%hu)\",\n+\t\t\t   bm->len);\n+\t\treturn -1;\n+\t}\n+\n+\tif (bm->len > sizeof(tbm->bitmap)) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: tbm len=%hu exceeds supported len=%zu\",\n+\t\t\t   bm->len, sizeof(tbm->bitmap));\n+\t\treturn -1;\n+\t}\n+\n+\tctrl = le_to_host16(bm->ctrl);\n+\n+\tduration_bit = BITS(ctrl, NAN_TIME_BM_CTRL_BIT_DURATION_MASK,\n+\t\t\t    NAN_TIME_BM_CTRL_BIT_DURATION_POS);\n+\n+\tif (duration_bit > NAN_TIME_BM_CTRL_BIT_DURATION_128_TU) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Invalid time bitmap duration\");\n+\t\treturn -1;\n+\t}\n+\n+\ttbm->duration = duration_bit;\n+\n+\ttbm->period = BITS(ctrl, NAN_TIME_BM_CTRL_PERIOD_MASK,\n+\t\t\t   NAN_TIME_BM_CTRL_PERIOD_POS);\n+\tif (tbm->period) {\n+\t\tperiod = BIT(6 + tbm->period);\n+\t} else {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Bitmap with period=0 is not supported\");\n+\t\treturn -1;\n+\t}\n+\n+\ttbm->offset = BITS(ctrl, NAN_TIME_BM_CTRL_START_OFFSET_MASK,\n+\t\t\t   NAN_TIME_BM_CTRL_START_OFFSET_POS);\n+\n+\tif (bm->len * 8 * BIT(4 + tbm->duration) > period) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: tbm is longer than the repeat period\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (tbm->offset * 16 > period) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: tbm offset %u exceeds period %u\",\n+\t\t\t   tbm->offset, period);\n+\t\treturn -1;\n+\t}\n+\n+\ttbm->len = bm->len;\n+\tos_memcpy(tbm->bitmap, bm->bitmap, tbm->len);\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * nan_parse_band_chan_list - Parse NAN Band/Channel List attribute\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @entry: On return would hold the parsed band/channel list\n+ * @list: Buffer holding the band/channel list\n+ * @len: Length of &list\n+ * Return 0 on success; otherwise -1\n+ */\n+static int nan_parse_band_chan_list(struct nan_data *nan,\n+\t\t\t\t    struct nan_avail_entry *entry,\n+\t\t\t\t    const struct nan_band_chan_list *list,\n+\t\t\t\t    u16 len)\n+{\n+\tu8 band_chan_size, non_cont, i;\n+\tconst u8 *pos;\n+\n+\tif (len < sizeof(*list)) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Too short channel/band list=%hu\", len);\n+\t\treturn -1;\n+\t}\n+\n+\tentry->band_chan_type = list->ctrl & NAN_BAND_CHAN_CTRL_TYPE;\n+\tentry->n_band_chan = BITS(list->ctrl,\n+\t\t\t\t  NAN_BAND_CHAN_CTRL_NUM_ENTRIES_MASK,\n+\t\t\t\t  NAN_BAND_CHAN_CTRL_NUM_ENTRIES_POS);\n+\n+\tlen -= sizeof(*list);\n+\tpos = list->entries;\n+\n+\tif (entry->band_chan_type == NAN_TYPE_BAND) {\n+\t\tif (!len || !entry->n_band_chan || len < entry->n_band_chan) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Truncated band list. len=%u, band_chan=%u\",\n+\t\t\t\t   len, entry->n_band_chan);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tentry->band_chan = os_zalloc(sizeof(*entry->band_chan) *\n+\t\t\t\t\t     entry->n_band_chan);\n+\t\tif (!entry->band_chan) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Failed to allocate band list\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tfor (i = 0; i < entry->n_band_chan; i++)\n+\t\t\tentry->band_chan[i].u.band_id = pos[i];\n+\n+\t\treturn 0;\n+\t}\n+\n+\tnon_cont = !!(list->ctrl & NAN_BAND_CHAN_CTRL_NON_CONT_BW);\n+\tband_chan_size = non_cont ? NAN_CHAN_ENRTY_80P80_LEN :\n+\t\tNAN_CHAN_ENRTY_MIN_LEN;\n+\n+\tif (len < entry->n_band_chan * band_chan_size) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Truncated channel list\");\n+\t\treturn -1;\n+\t}\n+\n+\tentry->band_chan = os_zalloc(sizeof(*entry->band_chan) *\n+\t\t\t\t     entry->n_band_chan);\n+\tif (!entry->band_chan) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Failed to allocate channel list\");\n+\t\treturn -1;\n+\t}\n+\n+\tfor (i = 0; i < entry->n_band_chan; i++) {\n+\t\tstruct nan_band_chan *curr = &entry->band_chan[i];\n+\t\tstruct nan_chan_entry *chan = (void *)pos;\n+\n+\t\tcurr->u.chan.op_class = chan->op_class;\n+\t\tcurr->u.chan.chan_bitmap = chan->chan_bitmap;\n+\t\tcurr->u.chan.pri_chan_bitmap = chan->pri_chan_bitmap;\n+\t\tif (non_cont)\n+\t\t\tcurr->u.chan.aux_chan_bitmap = chan->aux_chan_bitmap;\n+\n+\t\tpos += band_chan_size;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * nan_split_avail_entry - Split an availability entry\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @entry: Original entry to split\n+ * Returns a newly allocated potential entry on success, otherwise NULL.\n+ *\n+ * The function expects an availability entry which is both\n+ * committed/conditional and potential and has more then one channel entry. It\n+ * splits the original entry such that:\n+ *\n+ * - The original entry is only committed/conditional with one channel entry\n+ * - A new potential entry with the rest of the channels specified in the\n+ *   original entry.\n+ */\n+static struct nan_avail_entry *\n+nan_split_avail_entry(struct nan_data *nan,\n+\t\t      struct nan_avail_entry *entry)\n+{\n+\tstruct nan_avail_entry *pot;\n+\tstruct nan_band_chan *tmp;\n+\n+\twpa_printf(MSG_DEBUG,\n+\t\t   \"NAN: Split Committed/Conditional and potential entry\");\n+\n+\tpot = os_zalloc(sizeof(*pot));\n+\tif (!pot) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Failed to allocate availability entry\");\n+\t\treturn NULL;\n+\t}\n+\n+\tpot->map_id = entry->map_id;\n+\tpot->type = NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL;\n+\tpot->preference = entry->preference;\n+\tpot->utilization = entry->utilization;\n+\tpot->rx_nss = entry->rx_nss;\n+\n+\tdl_list_init(&pot->list);\n+\n+\tpot->tbm.duration = entry->tbm.duration;\n+\tpot->tbm.period = entry->tbm.period;\n+\tpot->tbm.offset = entry->tbm.offset;\n+\tpot->tbm.len = entry->tbm.len;\n+\n+\tos_memcpy(pot->tbm.bitmap, entry->tbm.bitmap, pot->tbm.len);\n+\n+\tpot->band_chan_type = entry->band_chan_type;\n+\tpot->n_band_chan = entry->n_band_chan - 1;\n+\tpot->band_chan = os_zalloc(sizeof(*pot->band_chan) *\n+\t\t\t\t   pot->n_band_chan);\n+\tif (!pot->band_chan) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Failed to allocate channel list: potential\");\n+\t\tos_free(pot);\n+\t\treturn NULL;\n+\t}\n+\n+\tos_memcpy(pot->band_chan, &entry->band_chan[1],\n+\t\t  sizeof(*pot->band_chan) * pot->n_band_chan);\n+\n+\ttmp = entry->band_chan;\n+\n+\t/* Clear potential from the original entry */\n+\tentry->type &= ~(NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL);\n+\tentry->band_chan = os_malloc(sizeof(*entry->band_chan));\n+\tif (!entry->band_chan) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Failed to allocate channel list: committed\");\n+\t\tos_free(pot->band_chan);\n+\t\tos_free(pot);\n+\t\treturn NULL;\n+\t}\n+\n+\tos_memcpy(entry->band_chan, tmp, sizeof(*entry->band_chan));\n+\tentry->n_band_chan = 1;\n+\n+\tos_free(tmp);\n+\treturn pot;\n+}\n+\n+\n+/*\n+ * nan_parse_avail_entry - Parse a NAN availability entry\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @peer_info: Peer info where the parsed entry would be added\n+ * @avail_entry: Pointer to the availability entry\n+ * @entry_len: Length of the availability entry\n+ * @map_id: Map ID of the availability attribute that this entry belongs to\n+ * Returns: 0 on success, -1 on failure, or 0 to skip the entry\n+ */\n+static int nan_parse_avail_entry(struct nan_data *nan,\n+\t\t\t\t struct nan_peer_info *peer_info,\n+\t\t\t\t const struct nan_avail_ent *avail_entry,\n+\t\t\t\t u16 entry_len, u8 map_id)\n+{\n+\tstruct nan_avail_entry *entry;\n+\tconst u8 *pos;\n+\tu16 ctrl, len;\n+\tu8 type, preference, utilization;\n+\n+\tif (entry_len < MIN_AVAIL_ENTRY_LEN) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Too short availability entry len=%hu\",\n+\t\t\t   entry_len);\n+\t\treturn -1;\n+\t}\n+\n+\tctrl = le_to_host16(avail_entry->ctrl);\n+\n+\ttype = ctrl & NAN_AVAIL_ENTRY_CTRL_TYPE_MASK;\n+\tif (!type ||\n+\t    ((type & NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED) &&\n+\t     (type & NAN_AVAIL_ENTRY_CTRL_TYPE_COND))) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Invalid entry type=0x%x\", type);\n+\t\treturn -1;\n+\t}\n+\n+\tpreference = BITS(ctrl, NAN_AVAIL_ENTRY_CTRL_USAGE_PREF_MASK,\n+\t\t\t  NAN_AVAIL_ENTRY_CTRL_USAGE_PREF_POS);\n+\tif (!preference && type == NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Skip potential entry with 0 usage preference\");\n+\t\treturn 0;\n+\t}\n+\n+\tutilization = BITS(ctrl, NAN_AVAIL_ENTRY_CTRL_UTIL_MASK,\n+\t\t\t   NAN_AVAIL_ENTRY_CTRL_UTIL_POS);\n+\n+\tif (utilization > NAN_AVAIL_ENTRY_CTRL_UTIL_MAX &&\n+\t    utilization != NAN_AVAIL_ENTRY_CTRL_UTIL_UNKNOWN) {\n+\t\twpa_printf(MSG_DEBUG, \"NAN: Invalid tbm utilization\");\n+\t\treturn -1;\n+\t}\n+\n+\twpa_printf(MSG_DEBUG,\n+\t\t   \"NAN: Avail entry: map_id=%u, ctrl=0x%04x, entry_len=%u, type=0x%x, pref=0x%x\",\n+\t\t   map_id, ctrl, entry_len, type, preference);\n+\n+\tentry = os_zalloc(sizeof(*entry));\n+\tif (!entry) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Failed to allocate availability entry\");\n+\t\treturn -1;\n+\t}\n+\n+\tentry->map_id = map_id;\n+\tentry->type = type;\n+\tentry->preference = preference;\n+\tentry->utilization = utilization;\n+\tdl_list_init(&entry->list);\n+\n+\tentry->rx_nss = BITS(ctrl, NAN_AVAIL_ENTRY_CTRL_RX_NSS_MASK,\n+\t\t\t     NAN_AVAIL_ENTRY_CTRL_RX_NSS_POS);\n+\tif (!entry->rx_nss) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Avail entry with rx_nss=0. Override to 1\");\n+\t\tentry->rx_nss = 1;\n+\t}\n+\n+\tlen = entry_len - MIN_AVAIL_ENTRY_LEN;\n+\tpos = avail_entry->optional;\n+\n+\tif (ctrl & NAN_AVAIL_ENTRY_CTRL_TBM_PRESENT) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Availability entry: Time bitmap is set\");\n+\n+\t\tif (len < sizeof(struct nan_tbm)) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Time bitmap set: length too short\");\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tif (nan_parse_tbm(nan, &entry->tbm, pos, len))\n+\t\t\tgoto out;\n+\n+\t\tpos += entry->tbm.len + sizeof(struct nan_tbm);\n+\t\tlen -= entry->tbm.len + sizeof(struct nan_tbm);\n+\t} else {\n+\t\tentry->tbm.len = 0;\n+\t\tos_memset(entry->tbm.bitmap, 0, sizeof(entry->tbm.bitmap));\n+\t}\n+\n+\tif (nan_parse_band_chan_list(nan, entry, (void *)pos, len))\n+\t\tgoto out;\n+\n+\t/*\n+\t * An entry with committed/conditional can either have a single channel\n+\t * entry, or multiple channel entries. The later case is allowed only if\n+\t * the entry is also potential, in which case the fist channel entry\n+\t * belongs to the committed entry and the other channels are potential\n+\t */\n+\tif ((entry->type & NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED) ||\n+\t    (entry->type & NAN_AVAIL_ENTRY_CTRL_TYPE_COND)) {\n+\t\tif (entry->band_chan_type != NAN_TYPE_CHANNEL) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Committed/cond avail entry with band\");\n+\t\t\tgoto out;\n+\t\t} else if (entry->n_band_chan < 1) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Committed/cond avail entry: no channels\");\n+\t\t\tgoto out;\n+\t\t} else if (entry->n_band_chan > 1) {\n+\t\t\tstruct nan_avail_entry *pot_avail;\n+\n+\t\t\tif (!(entry->type &\n+\t\t\t      NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL)) {\n+\t\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t\t   \"NAN: Committed/cond avail entry: %u chans\",\n+\t\t\t\t\t   entry->n_band_chan);\n+\t\t\t\tgoto out;\n+\t\t\t}\n+\n+\t\t\tpot_avail = nan_split_avail_entry(nan, entry);\n+\t\t\tif (!pot_avail)\n+\t\t\t\tgoto out;\n+\n+\t\t\tdl_list_add(&peer_info->avail_entries,\n+\t\t\t\t    &pot_avail->list);\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * Committed/conditional with single channel entry.\n+\t\t\t * Clear the potential in case that it is set.\n+\t\t\t */\n+\t\t\tentry->type &= ~(NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL);\n+\t\t}\n+\t}\n+\n+\tdl_list_add(&peer_info->avail_entries, &entry->list);\n+\treturn 0;\n+\n+out:\n+\tnan_del_avail_entry(entry);\n+\treturn -1;\n+}\n+\n+\n+/*\n+ * nan_parse_avail_attr - Parse NAN Availability attribute\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @peer_info: Peer info where the parsed entries would be added\n+ * @avail_attr: Pointer to the availability attribute\n+ *\n+ * Parse availability attribute as defined in Wi-Fi Aware Specification\n+ * v4.0 section 9.5.17.1\n+ */\n+static int nan_parse_avail_attr(struct nan_data *nan,\n+\t\t\t\tstruct nan_peer_info *peer_info,\n+\t\t\t\tconst struct nan_avail *avail_attr,\n+\t\t\t\tu16 attr_len)\n+{\n+\tu8 map_id;\n+\tconst u8 *entries;\n+\tu16 ctrl, entries_len;\n+\n+\twpa_printf(MSG_DEBUG, \"NAN: Parse avail attr: len=%u\", attr_len);\n+\n+\tctrl = le_to_host16(avail_attr->ctrl);\n+\tmap_id = ctrl & NAN_AVAIL_CTRL_MAP_ID_MASK;\n+\n+\tentries = avail_attr->optional;\n+\tentries_len = attr_len - sizeof(*avail_attr);\n+\tif (!entries_len) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Availability attribute without any entries\");\n+\t\treturn -1;\n+\t}\n+\n+\twhile (entries_len > 2) {\n+\t\tu16 entry_len = WPA_GET_LE16(entries);\n+\t\tconst struct nan_avail_ent *avail_entry = (void *)entries;\n+\n+\t\tif (entry_len + 2 > entries_len) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Truncated availability entry\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (nan_parse_avail_entry(nan, peer_info, avail_entry,\n+\t\t\t\t\t  entry_len, map_id))\n+\t\t\treturn -1;\n+\n+\t\tentries += entry_len + 2;\n+\t\tentries_len -= entry_len + 2;\n+\t}\n+\n+\tif (entries_len) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Availability entries list truncated\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static void nan_peer_dump_info(struct nan_data *nan, struct nan_peer_info *info)\n+{\n+\tstruct nan_avail_entry *entry;\n+\n+\twpa_printf(MSG_DEBUG,\n+\t\t   \"NAN: info: seen=%lu.%lu, seq_id=%u\",\n+\t\t   info->last_seen.sec, info->last_seen.usec,\n+\t\t   info->seq_id);\n+\n+\tdl_list_for_each(entry, &info->avail_entries, struct nan_avail_entry,\n+\t\t\t list) {\n+\t\tu8 i;\n+\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: entry: map_id=%u, type=0x%x, pref=%u, util=%u\",\n+\t\t\t   entry->map_id, entry->type, entry->preference,\n+\t\t\t   entry->utilization);\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: entry: band_channel_type=%u, n_band_chan=%u\",\n+\t\t\t   entry->band_chan_type, entry->n_band_chan);\n+\n+\t\tfor (i = 0; i < entry->n_band_chan; i++) {\n+\t\t\tstruct nan_band_chan *bc = &entry->band_chan[i];\n+\n+\t\t\tif (entry->type == NAN_TYPE_BAND)\n+\t\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t\t   \"NAN: band: %u\", bc->u.band_id);\n+\t\t\telse\n+\t\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t\t   \"NAN: channel: oc=%u, cbtm=0x%x, pcbtm=0x%x\",\n+\t\t\t\t\t   bc->u.chan.op_class,\n+\t\t\t\t\t   bc->u.chan.chan_bitmap,\n+\t\t\t\t\t   bc->u.chan.pri_chan_bitmap);\n+\t\t}\n+\t}\n+}\n+\n+\n+static void nan_peer_dump(struct nan_data *nan, struct nan_peer *peer)\n+{\n+\twpa_printf(MSG_DEBUG,\n+\t\t   \"NAN: peer: \" MACSTR \" last_seen=%lu.%lu\",\n+\t\t   MAC2STR(peer->nmi_addr), peer->last_seen.sec,\n+\t\t   peer->last_seen.usec);\n+\n+\tnan_peer_dump_info(nan, &peer->info);\n+}\n+\n+\n+/*\n+ * Update the old peer info with information from the new peer info.\n+ * Information that is available in the old peer info but is not available\n+ * in the new peer info will not be changed.\n+ */\n+static void nan_merge_peer_info(struct nan_peer_info *old,\n+\t\t\t\tstruct nan_peer_info *new)\n+{\n+\tif (!dl_list_empty(&new->avail_entries)) {\n+\t\tstruct nan_avail_entry *avail, *tmp;\n+\n+\t\tnan_peer_flush_avail(old);\n+\t\tdl_list_init(&old->avail_entries);\n+\n+\t\tdl_list_for_each_safe(avail, tmp, &new->avail_entries,\n+\t\t\t\t      struct nan_avail_entry, list) {\n+\t\t\tdl_list_del(&avail->list);\n+\t\t\tdl_list_add(&old->avail_entries, &avail->list);\n+\t\t}\n+\t\told->seq_id = new->seq_id;\n+\t}\n+\n+\told->last_seen = new->last_seen;\n+}\n+\n+\n+static int nan_avail_info(struct nan_data *nan, struct nan_peer *peer,\n+\t\t\t  struct nan_attrs *attrs, struct nan_peer_info *info)\n+{\n+\tstruct nan_avail *avail_attr;\n+\tstruct nan_attrs_entry *attr;\n+\n+\tattr = dl_list_first(&attrs->avail, struct nan_attrs_entry, list);\n+\tif (!attr)\n+\t\treturn 0;\n+\n+\tavail_attr = (void *)attr->ptr;\n+\n+\t/*\n+\t * The sequence id may wrap around, so if the received\n+\t * sequence id is much smaller than the sequence id of\n+\t * the last update, assume it has wrapped around and\n+\t * accept the new schedule. Otherwise ignore it as an old\n+\t * schedule.\n+\t */\n+\tif (!dl_list_empty(&peer->info.avail_entries) &&\n+\t    peer->info.seq_id >= avail_attr->seq_id &&\n+\t    peer->info.seq_id - avail_attr->seq_id < 128) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Ignore peer avail update: seq_id=%hhu, seq_id=%hhu\",\n+\t\t\t   avail_attr->seq_id, peer->info.seq_id);\n+\t\treturn 0;\n+\t}\n+\n+\tinfo->seq_id = avail_attr->seq_id;\n+\n+\tdl_list_for_each(attr, &attrs->avail, struct nan_attrs_entry, list) {\n+\t\tavail_attr = (void *)attr->ptr;\n+\n+\t\tif (avail_attr->seq_id != info->seq_id) {\n+\t\t\twpa_printf(MSG_DEBUG,\n+\t\t\t\t   \"NAN: Not all avail attributes have the same seq_id\");\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tif (nan_parse_avail_attr(nan, info, avail_attr, attr->len))\n+\t\t\tgoto out;\n+\t}\n+\n+\treturn 0;\n+out:\n+\tnan_peer_flush_avail(info);\n+\treturn -1;\n+}\n+\n+\n+/*\n+ * nan_parse_device_attrs - Parse device attributes and build availability info\n+ *\n+ * @nan: NAN module context from nan_init()\n+ * @peer: NAN peer\n+ * @attrs_data: Buffer holding the device attributes\n+ * @attrs_len: Length of &attrs_data in octets\n+ * Return 0 on success; -1 otherwise.\n+ */\n+int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,\n+\t\t\t   const u8 *attrs_data, size_t attrs_len)\n+{\n+\tstruct nan_peer_info info;\n+\tstruct nan_attrs attrs;\n+\tint ret;\n+\n+\tos_memset(&info, 0, sizeof(info));\n+\tdl_list_init(&info.avail_entries);\n+\tos_get_reltime(&info.last_seen);\n+\n+\tif (nan_parse_attrs(nan, attrs_data, attrs_len, &attrs)) {\n+\t\twpa_printf(MSG_DEBUG,\n+\t\t\t   \"NAN: Failed to parse peer \" MACSTR \" attributes\",\n+\t\t\t   MAC2STR(peer->nmi_addr));\n+\t\treturn -1;\n+\t}\n+\n+\tif (nan_avail_info(nan, peer, &attrs, &info)) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\tnan_merge_peer_info(&peer->info, &info);\n+\tnan_peer_dump(nan, peer);\n+\tret = 0;\n+out:\n+\tnan_attrs_clear(nan, &attrs);\n+\treturn ret;\n+}\n+\n+\n static struct nan_peer *nan_alloc_peer(struct nan_data *nan)\n {\n \tstruct nan_peer *peer, *oldest = NULL;\n@@ -208,6 +860,7 @@ static struct nan_peer *nan_alloc_peer(struct nan_data *nan)\n \tif (!peer)\n \t\treturn NULL;\n \n+\tdl_list_init(&peer->info.avail_entries);\n \tdl_list_add(&nan->peer_list, &peer->list);\n \tdl_list_init(&peer->ndps);\n \treturn peer;\ndiff --git a/src/nan/nan_i.h b/src/nan/nan_i.h\nindex 1ff6e4dbba..3a268940fc 100644\n--- a/src/nan/nan_i.h\n+++ b/src/nan/nan_i.h\n@@ -100,11 +100,84 @@ struct nan_ndp_setup {\n \tu8 service_id[NAN_SERVICE_ID_LEN];\n };\n \n+/*\n+ * struct nan_band_chan - NAN channel/band entry\n+ *\n+ * @band_id: Band ID as specified by enum nan_band_entry.\n+ * @chan: Channel entry as specified by &struct nan_chan_entry.\n+ */\n+struct nan_band_chan {\n+\tunion {\n+\t\tu8 band_id;\n+\t\tstruct nan_chan_entry chan;\n+\t} u;\n+};\n+\n+/**\n+ * enum nan_band_chan_type - NAN band or channel\n+ *\n+ * @NAN_TYPE_BAND: The entry is a band entry\n+ * @NAN_TYPE_CHANNEL: The entry is a channel entry\n+ */\n+enum nan_band_chan_type {\n+\tNAN_TYPE_BAND,\n+\tNAN_TYPE_CHANNEL,\n+};\n+\n+/*\n+ * struct nan_avail_entry - NAN availability entry\n+ *\n+ * @list: Used for linking in the availability entries list.\n+ * @map_id: Map id of the availability attribute that this entry belongs to.\n+ * @type: Availability type. One of NAN_AVAIL_ENTRY_CTRL_TYPE_*.\n+ * @preference: Preference of being available in the NAN slots specified by\n+ *\tthe associated time bitmap. The preference is higher when the value is\n+ *\tset larger. Valid values are 0 - 3.\n+ * @utilization: Indicating proportion within the NAN slots specified by the\n+ *\tassociated time bitmap that are already utilized for other purposes,\n+ *\tquantized to 20%. Valid values are 0 - 5.\n+ * @rx_nss: Max number of special streams the NAN device can receive during\n+ *\tthe NAN slots specified by the associated time bitmap.\n+ * @tbm: Time bitmap specifying the NAN slots in which the device will be\n+ *\tavailable for NAN operations.\n+ * @band_chan_type: Type of entries in &band_chan array, as specified by\n+ *\tenum nan_band_chan_type.\n+ * @n_band_chan: Number of entries in &band_chan array.\n+ * @band_chan: Array of bands/channels on which the NAN device will be\n+ *\tavailable.\n+ */\n+struct nan_avail_entry {\n+\tstruct dl_list list;\n+\tu8 map_id;\n+\tu8 type;\n+\tu8 preference;\n+\tu8 utilization;\n+\tu8 rx_nss;\n+\tstruct nan_time_bitmap tbm;\n+\tenum nan_band_chan_type band_chan_type;\n+\tu8 n_band_chan;\n+\tstruct nan_band_chan *band_chan;\n+};\n+\n+/*\n+ * struct nan_peer_info - NAN peer information\n+ *\n+ * @last_seen: Timestamp of the last update of the peer info.\n+ * @seq_id: Sequence id of the last availability update.\n+ * @avail_entries: List of availability entries of the peer.\n+ */\n+struct nan_peer_info {\n+\tstruct os_reltime last_seen;\n+\tu8 seq_id;\n+\tstruct dl_list avail_entries;\n+};\n+\n /**\n  * struct nan_peer - Represents a known NAN peer\n  * @list: List node for linking peers.\n  * @nmi_addr: NAN MAC address of the peer.\n  * @last_seen: Timestamp of the last time this peer was seen.\n+ * @info: Information about the peer.\n  * @ndps: List of NDPs associated with this peer.\n  * @ndp_setup: Used to hold an NDP object while NDP establishment is in\n  *     progress.\n@@ -113,6 +186,8 @@ struct nan_peer {\n \tstruct dl_list list;\n \tu8 nmi_addr[ETH_ALEN];\n \tstruct os_reltime last_seen;\n+\tstruct nan_peer_info info;\n+\n \tstruct dl_list ndps;\n \n \tstruct nan_ndp_setup ndp_setup;\n@@ -215,4 +290,6 @@ void nan_ndp_setup_failure(struct nan_data *nan, struct nan_peer *peer,\n \t\t\t   enum nan_reason reason, bool reset_state);\n int nan_ndp_naf_sent(struct nan_data *nan, struct nan_peer *peer,\n \t\t     enum nan_subtype subtype);\n+int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,\n+\t\t\t   const u8 *attrs_data, size_t attrs_len);\n #endif /* NAN_I_H */\n",
    "prefixes": [
        "12/58"
    ]
}