{"id":2234747,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2234747/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-13-alistair.francis@wdc.com/","project":{"id":28,"url":"http://patchwork.ozlabs.org/api/1.2/projects/28/?format=json","name":"Linux PCI development","link_name":"linux-pci","list_id":"linux-pci.vger.kernel.org","list_email":"linux-pci@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260508031710.514574-13-alistair.francis@wdc.com>","list_archive_url":null,"date":"2026-05-08T03:17:04","name":"[12/18] lib: rspdm: Support SPDM get_capabilities","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"a8a13e23806b7fa092ae4aceddae9e2945abd85b","submitter":{"id":64571,"url":"http://patchwork.ozlabs.org/api/1.2/people/64571/?format=json","name":"Alistair Francis","email":"alistair23@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-13-alistair.francis@wdc.com/mbox/","series":[{"id":503312,"url":"http://patchwork.ozlabs.org/api/1.2/series/503312/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/list/?series=503312","date":"2026-05-08T03:16:52","name":"lib: Rust implementation of SPDM","version":1,"mbox":"http://patchwork.ozlabs.org/series/503312/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2234747/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2234747/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-pci+bounces-54167-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=s5yyXS3T;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-54167-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"s5yyXS3T\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.214.169","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBZDl3Cvcz1yK7\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 13:22:31 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 2ED2030701AC\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 03:19:28 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 2B8CA3101A9;\n\tFri,  8 May 2026 03:19:00 +0000 (UTC)","from mail-pl1-f169.google.com (mail-pl1-f169.google.com\n [209.85.214.169])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id AE60D30EF82\n\tfor <linux-pci@vger.kernel.org>; Fri,  8 May 2026 03:18:55 +0000 (UTC)","by mail-pl1-f169.google.com with SMTP id\n d9443c01a7336-2ba4efedbeaso11157435ad.1\n        for <linux-pci@vger.kernel.org>; Thu, 07 May 2026 20:18:55 -0700 (PDT)","from toolbx.alistair23.me ([2403:581e:fdf9:0:6209:4521:6813:45b7])\n        by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2baf1eafa62sm3220685ad.74.2026.05.07.20.18.47\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Thu, 07 May 2026 20:18:53 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778210338; cv=none;\n b=LBgP2DpN1NPWSFzbx+BYBZAFiOa64PWfjRf64oMAJyREde/27m7BFs8qvvhvAsF5mK3/iOZ59b/LQ3Y1DJX47ZKIXsrzf9+E2AvSP3V2EwRmCl7sJy4m94+8ifa/gr+A5hzw/43Q1C2NEwMOpwVz1sqTslmt0CQ+uux50Yw+uXY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778210338; c=relaxed/simple;\n\tbh=pgki4w7RWc81YTCI0ulFXlX7HnZjkRUDYahaKFjwBrY=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=ezYwqilrygEe+IvAG0FVTFB49PECSGfS/Qd1k1bLCDzLbvbKQ5eMrGo8/CzMyScnP4XdfycMb7Oaa/J3IqnqRyMwnuOFYE+N6tncEB/Hg3kMWZyoes+J4hWbH/Ig8Yw3PXiDu6G1HMiQ9ISsk5xoztoARsuTbwQiKvqPA7RuA3o=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=s5yyXS3T; arc=none smtp.client-ip=209.85.214.169","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1778210334; x=1778815134;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=VcbWqg6jBmtAgedbxHyaToXZ0xvL9n8c+k1cA5Ncp9c=;\n        b=s5yyXS3Tq4hRomHX1+ENW+n73wPP/CbxuD5Z8LCDEw94z6LeEdsEortXwfia4YNHBc\n         SCp52PXZzYkRqZ9fJH0zSeHgLFV37EmA1Bdls8ffa59xfqstqR10e9P7KOmbb4dQ1TcB\n         LZ3MmpZfkaHaW+kAluIGe8VVjvmfJg2gCb+k22Z8LKpRJgZvnXBLhXWyCKPtM1JfvBSE\n         mq+q4x0VnncjdqnT6x96kRQO8tfvFW7aA2ItuIV7bEBuiE3j6j7BavoPSNkwUyec+90g\n         80p5kRgWWMTz/WIX6xGYRLA1m7K404OXvjheprNDtMgThPc7BUs1yuv80QoA1xDWLweP\n         GlKQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1778210334; x=1778815134;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=VcbWqg6jBmtAgedbxHyaToXZ0xvL9n8c+k1cA5Ncp9c=;\n        b=XZ81/B2Hfi5alsQXf8aOS0jbmJp4i5K8jzxnE3yYg7M7KFbcRASs34HzyRLAXdREhK\n         YUTF/ir6IYHIbFxnPLraQvygJY0rvF8ehmTxP/WoYGE6i0uc1DmxGXZHpnuJtjh/94AH\n         hy7breOk+iRQgd2xrHziITZ4TGeoUVL13cBPbAys8+yUzCb7/1Q8ScqQrmugOA9/W6O6\n         M97g/3vZwjGU3mrwiEnSOAe5eAM74B1V4kNyR1xHrJqcXdEz5fxL4XUtqNUfNUA+R3OM\n         9JsVenI4E0C0Z9v/MEKdlg5NDJNK/Ar+SuFQLvvhfDhjk3RtR9T5coAiKaGf2yEF+i+9\n         DgTA==","X-Forwarded-Encrypted":"i=1;\n AFNElJ+wpcno1nMdY8WrYO0ztQEvRMh1KIxBDdBJ8u6vIPtcpHiBQYji2b1dj9GR9uGN5WBg0uRfM2MN7Lw=@vger.kernel.org","X-Gm-Message-State":"AOJu0YwGqYeeOrkDXNEfoLTS2mjLNxenb2w/Xv3RnH5+t5c8igbAWwyh\n\tWG8/A6bm0WAMdAgRIQkwodLZlJg6fpRn37FpgDjlaKsYmU9grfRzKD5H","X-Gm-Gg":"Acq92OFpA1I0bRL1q0remoOLDH5+alS1NV+ZHmRHDmi4ML7U9yRnX6Dc3Hr6CuTNXfM\n\t+P+Ce6g/zlOqrtvTXVfiWubQhTvJIQp+359DaLfsYEtjD1gQmX3uQfUjmYaZSDT/ub8zUlQbHRw\n\tYufnqSPtukihT7rnIrdtr1FSQDBxs9oteslUslVuImql68MrtIQBoSQ3D6Wuly1d4fmIERQc9IF\n\tgVMNkHiLHq0B8dHWhZ2F5std3zs5YHn+1PlSM2TUts4gdHFkB3LaubBYM6taCfi1qDou7OxYww3\n\tOVu/72gC4iYwUMTcNPGFJjK3kLi08ohEeKnejVSwjmAHQAB6ecC8nLfUrCuksslsIysOOisdzX+\n\tippMiuPY8W+043ycy7bsJ+UpYgjRSHAdb61XLgJJPA/OZ6+b8wopgf2byzJLoILmv++mXNaFspP\n\tbRHcrGkiCB+uRKCF3LhMaT9Ybjn17R1GNTomEzqFJojCO7HCpOwT8=","X-Received":"by 2002:a17:902:fa07:b0:2b2:549f:7d2b with SMTP id\n d9443c01a7336-2ba794b9766mr73480655ad.11.1778210334411;\n        Thu, 07 May 2026 20:18:54 -0700 (PDT)","From":"alistair23@gmail.com","X-Google-Original-From":"alistair.francis@wdc.com","To":"alistair@alistair23.me,\n\tlinux-kernel@vger.kernel.org,\n\tlukas@wunner.de,\n\tJonathan.Cameron@huawei.com,\n\tbhelgaas@google.com,\n\trust-for-linux@vger.kernel.org,\n\takpm@linux-foundation.org,\n\tlinux-cxl@vger.kernel.org,\n\tdjbw@kernel.org,\n\tlinux-pci@vger.kernel.org","Cc":"alex.gaynor@gmail.com,\n\twilfred.mallawa@wdc.com,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tbenno.lossin@proton.me,\n\taliceryhl@google.com,\n\tboqun.feng@gmail.com,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu,\n\tojeda@kernel.org,\n\talistair23@gmail.com","Subject":"[PATCH 12/18] lib: rspdm: Support SPDM get_capabilities","Date":"Fri,  8 May 2026 13:17:04 +1000","Message-ID":"<20260508031710.514574-13-alistair.francis@wdc.com>","X-Mailer":"git-send-email 2.52.0","In-Reply-To":"<20260508031710.514574-1-alistair.francis@wdc.com>","References":"<20260508031710.514574-1-alistair.francis@wdc.com>","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"From: Alistair Francis <alistair@alistair23.me>\n\nSupport the GET_CAPABILITIES SPDM command.\n\nSigned-off-by: Alistair Francis <alistair@alistair23.me>\n---\n lib/rspdm/consts.rs    | 19 ++++++++-\n lib/rspdm/lib.rs       |  4 ++\n lib/rspdm/state.rs     | 76 ++++++++++++++++++++++++++++++++-\n lib/rspdm/validator.rs | 97 +++++++++++++++++++++++++++++++++++++++++-\n 4 files changed, 192 insertions(+), 4 deletions(-)","diff":"diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs\nindex 5482a0f6cee0..ef7d2d1d8e6e 100644\n--- a/lib/rspdm/consts.rs\n+++ b/lib/rspdm/consts.rs\n@@ -9,12 +9,11 @@\n \n use crate::validator::SpdmHeader;\n use core::mem;\n+use kernel::bits::bit_u32;\n \n /* SPDM versions supported by this implementation */\n pub(crate) const SPDM_VER_10: u8 = 0x10;\n-#[allow(dead_code)]\n pub(crate) const SPDM_VER_11: u8 = 0x11;\n-#[allow(dead_code)]\n pub(crate) const SPDM_VER_12: u8 = 0x12;\n #[allow(dead_code)]\n pub(crate) const SPDM_VER_13: u8 = 0x13;\n@@ -68,3 +67,19 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n \n pub(crate) const SPDM_GET_VERSION: u8 = 0x84;\n pub(crate) const SPDM_GET_VERSION_LEN: usize = mem::size_of::<SpdmHeader>() + u8::MAX as usize;\n+\n+pub(crate) const SPDM_GET_CAPABILITIES: u8 = 0xe1;\n+pub(crate) const SPDM_MIN_DATA_TRANSFER_SIZE: u32 = 42;\n+\n+// SPDM cryptographic timeout of this implementation:\n+// Assume calculations may take up to 1 sec on a busy machine, which equals\n+// roughly 1 << 20.  That's within the limits mandated for responders by CMA\n+// (1 << 23 usec, PCIe r6.2 sec 6.31.3) and DOE (1 sec, PCIe r6.2 sec 6.30.2).\n+// Used in GET_CAPABILITIES exchange.\n+pub(crate) const SPDM_CTEXPONENT: u8 = 20;\n+\n+pub(crate) const SPDM_CERT_CAP: u32 = bit_u32(1);\n+pub(crate) const SPDM_CHAL_CAP: u32 = bit_u32(2);\n+\n+pub(crate) const SPDM_REQ_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP;\n+pub(crate) const SPDM_RSP_MIN_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP;\ndiff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs\nindex 1cc6c33516fb..9628f258854c 100644\n--- a/lib/rspdm/lib.rs\n+++ b/lib/rspdm/lib.rs\n@@ -112,6 +112,10 @@\n         return e.to_errno() as c_int;\n     }\n \n+    if let Err(e) = state.get_capabilities() {\n+        return e.to_errno() as c_int;\n+    }\n+\n     0\n }\n \ndiff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs\nindex 26b90942b298..e7119ffa9a69 100644\n--- a/lib/rspdm/state.rs\n+++ b/lib/rspdm/state.rs\n@@ -25,10 +25,17 @@\n     SPDM_ERROR,\n     SPDM_GET_VERSION_LEN,\n     SPDM_MAX_VER,\n+    SPDM_MIN_DATA_TRANSFER_SIZE,\n     SPDM_MIN_VER,\n-    SPDM_REQ, //\n+    SPDM_REQ,\n+    SPDM_RSP_MIN_CAPS,\n+    SPDM_VER_10,\n+    SPDM_VER_11,\n+    SPDM_VER_12, //\n };\n use crate::validator::{\n+    GetCapabilitiesReq,\n+    GetCapabilitiesRsp,\n     GetVersionReq,\n     GetVersionRsp,\n     SpdmErrorRsp,\n@@ -47,6 +54,8 @@\n ///\n /// `version`: Maximum common supported version of requester and responder.\n ///  Negotiated during GET_VERSION exchange.\n+/// @rsp_caps: Cached capabilities of responder.\n+///  Received during GET_CAPABILITIES exchange.\n #[expect(dead_code)]\n pub struct SpdmState {\n     pub(crate) dev: *mut bindings::device,\n@@ -57,6 +66,7 @@ pub struct SpdmState {\n \n     // Negotiated state\n     pub(crate) version: u8,\n+    pub(crate) rsp_caps: u32,\n }\n \n impl SpdmState {\n@@ -74,6 +84,7 @@ pub(crate) fn new(\n             transport_sz,\n             validate,\n             version: SPDM_MIN_VER,\n+            rsp_caps: 0,\n         }\n     }\n \n@@ -293,4 +304,67 @@ pub(crate) fn get_version(&mut self) -> Result<(), Error> {\n \n         Ok(())\n     }\n+\n+    /// Obtain the supported capabilities from an SPDM session and store the\n+    /// information in the `SpdmState`.\n+    pub(crate) fn get_capabilities(&mut self) -> Result<(), Error> {\n+        let mut request = GetCapabilitiesReq::default();\n+        request.version = self.version;\n+\n+        let (req_sz, rsp_sz) = match self.version {\n+            SPDM_VER_10 => (4, 8),\n+            SPDM_VER_11 => (8, 8),\n+            _ => {\n+                request.data_transfer_size = self.transport_sz.to_le();\n+                request.max_spdm_msg_size = request.data_transfer_size;\n+\n+                (\n+                    core::mem::size_of::<GetCapabilitiesReq>(),\n+                    core::mem::size_of::<GetCapabilitiesRsp>(),\n+                )\n+            }\n+        };\n+\n+        // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice\n+        let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) };\n+\n+        let mut response_vec: KVec<u8> = KVec::with_capacity(rsp_sz, GFP_KERNEL)?;\n+        // SAFETY: `response_vec` is rsp_sz length, initialised, aligned\n+        // and won't be mutated\n+        let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) };\n+\n+        let rc = self.spdm_exchange(request_buf, response_buf)?;\n+\n+        if rc < (rsp_sz as i32) {\n+            pr_err!(\"Truncated capabilities response\\n\");\n+            to_result(-(bindings::EIO as i32))?;\n+        }\n+\n+        // SAFETY: `rc` is the length of data read, which will be smaller\n+        // or the same as the capacity of the vector\n+        unsafe { response_vec.inc_len(rc as usize) };\n+\n+        let response: &mut GetCapabilitiesRsp =\n+            Untrusted::new_mut(&mut response_vec).validate_mut()?;\n+\n+        self.rsp_caps = u32::from_le(response.flags);\n+        if (self.rsp_caps & SPDM_RSP_MIN_CAPS) != SPDM_RSP_MIN_CAPS {\n+            pr_err!(\n+                \"{:#x} capabilities are supported, which don't meet required {:#x}\",\n+                self.rsp_caps,\n+                SPDM_RSP_MIN_CAPS\n+            );\n+            to_result(-(bindings::EPROTONOSUPPORT as i32))?;\n+        }\n+\n+        if self.version >= SPDM_VER_12 {\n+            if response.data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE {\n+                pr_err!(\"Malformed capabilities response\\n\");\n+                to_result(-(bindings::EPROTO as i32))?;\n+            }\n+            self.transport_sz = self.transport_sz.min(response.data_transfer_size);\n+        }\n+\n+        Ok(())\n+    }\n }\ndiff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs\nindex 8f45bafd4d69..7dc55882c880 100644\n--- a/lib/rspdm/validator.rs\n+++ b/lib/rspdm/validator.rs\n@@ -26,8 +26,12 @@\n };\n \n use crate::consts::{\n+    SPDM_CTEXPONENT,\n+    SPDM_GET_CAPABILITIES,\n     SPDM_GET_VERSION,\n-    SPDM_MIN_VER, //\n+    SPDM_MIN_VER,\n+    SPDM_REQ_CAPS, //\n+    SPDM_VER_11,\n };\n \n #[repr(C, packed)]\n@@ -141,3 +145,94 @@ fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err>\n         Ok(rsp)\n     }\n }\n+\n+#[repr(C, packed)]\n+pub(crate) struct GetCapabilitiesReq {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    pub(crate) param1: u8,\n+    pub(crate) param2: u8,\n+\n+    reserved1: u8,\n+    pub(crate) ctexponent: u8,\n+    reserved2: [u8; 2],\n+\n+    pub(crate) flags: u32,\n+\n+    /* End of SPDM 1.1 structure */\n+    pub(crate) data_transfer_size: u32,\n+    pub(crate) max_spdm_msg_size: u32,\n+}\n+\n+impl Default for GetCapabilitiesReq {\n+    fn default() -> Self {\n+        GetCapabilitiesReq {\n+            version: 0,\n+            code: SPDM_GET_CAPABILITIES,\n+            param1: 0,\n+            param2: 0,\n+            reserved1: 0,\n+            ctexponent: SPDM_CTEXPONENT,\n+            reserved2: [0; 2],\n+            flags: (SPDM_REQ_CAPS as u32).to_le(),\n+            data_transfer_size: 0,\n+            max_spdm_msg_size: 0,\n+        }\n+    }\n+}\n+\n+#[repr(C, packed)]\n+pub(crate) struct GetCapabilitiesRsp {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    pub(crate) param1: u8,\n+    param2: u8,\n+\n+    reserved1: u8,\n+    pub(crate) ctexponent: u8,\n+    reserved2: [u8; 2],\n+\n+    pub(crate) flags: u32,\n+\n+    /* End of SPDM 1.1 structure */\n+    pub(crate) data_transfer_size: u32,\n+    pub(crate) max_spdm_msg_size: u32,\n+\n+    pub(crate) supported_algorithms: __IncompleteArrayField<__le16>,\n+}\n+\n+impl Validate<&mut Unvalidated<KVec<u8>>> for &mut GetCapabilitiesRsp {\n+    type Err = Error;\n+\n+    fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err> {\n+        let raw = unvalidated.raw_mut();\n+\n+        if raw.len() < mem::size_of::<GetCapabilitiesRsp>() {\n+            let version = *(raw.get(0).ok_or(ENOMEM))?;\n+            let version_1_1_len = mem::size_of::<GetCapabilitiesRsp>()\n+                - mem::size_of::<__IncompleteArrayField<__le16>>()\n+                - mem::size_of::<u32>()\n+                - mem::size_of::<u32>();\n+\n+            if version == SPDM_VER_11 && raw.len() == version_1_1_len {\n+                // Version 1.1 of the spec doesn't include all of the fields\n+                // So let's extend the KVec with 0s so we can cast the\n+                // vector to GetCapabilitiesRsp\n+\n+                for _i in version_1_1_len..mem::size_of::<GetCapabilitiesRsp>() {\n+                    raw.push(0, GFP_KERNEL)?;\n+                }\n+            } else {\n+                return Err(EINVAL);\n+            }\n+        }\n+\n+        let ptr = raw.as_mut_ptr();\n+        // CAST: `GetCapabilitiesRsp` only contains integers and has `repr(C)`.\n+        let ptr = ptr.cast::<GetCapabilitiesRsp>();\n+        // SAFETY: `ptr` came from a reference and the cast above is valid.\n+        let rsp: &mut GetCapabilitiesRsp = unsafe { &mut *ptr };\n+\n+        Ok(rsp)\n+    }\n+}\n","prefixes":["12/18"]}