1691668feSPatrick Williams /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H 3c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H 4c63f63a2SAndrew Jeffery 566c7723aSAndrew Jeffery /* 666c7723aSAndrew Jeffery * Historically, many of the structs exposed in libpldm's public headers are 766c7723aSAndrew Jeffery * defined with __attribute__((packed)). This is unfortunate: it gives the 866c7723aSAndrew Jeffery * impression that a wire-format buffer can be cast to the message type to make 966c7723aSAndrew Jeffery * the message's fields easily accessible. As it turns out, that's not 1066c7723aSAndrew Jeffery * that's valid for several reasons: 1166c7723aSAndrew Jeffery * 1266c7723aSAndrew Jeffery * 1. Casting the wire-format buffer to a struct of the message type doesn't 1366c7723aSAndrew Jeffery * abstract the endianness of message field values 1466c7723aSAndrew Jeffery * 1566c7723aSAndrew Jeffery * 2. Some messages contain packed tagged union fields which cannot be properly 1666c7723aSAndrew Jeffery * described in a C struct. 1766c7723aSAndrew Jeffery * 1866c7723aSAndrew Jeffery * The msgbuf APIs exist to assist with (un)packing the wire-format in a way 1966c7723aSAndrew Jeffery * that is type-safe, spatially memory-safe, endian-safe, performant, and 2066c7723aSAndrew Jeffery * free of undefined-behaviour. Message structs that are added to the public 2166c7723aSAndrew Jeffery * library API should no-longer be marked __attribute__((packed)), and the 2266c7723aSAndrew Jeffery * implementation of their encode and decode functions must exploit the msgbuf 2366c7723aSAndrew Jeffery * API. 2466c7723aSAndrew Jeffery * 2566c7723aSAndrew Jeffery * However, we would like to allow implementation of codec functions in terms of 2666c7723aSAndrew Jeffery * msgbuf APIs even if they're decoding a message into a (historically) packed 2766c7723aSAndrew Jeffery * struct. Some of the complexity that follows is a consequence of the packed/ 2866c7723aSAndrew Jeffery * unpacked conflict. 2966c7723aSAndrew Jeffery */ 3066c7723aSAndrew Jeffery 31c63f63a2SAndrew Jeffery #ifdef __cplusplus 3237dd6a3dSAndrew Jeffery /* 3337dd6a3dSAndrew Jeffery * Fix up C11's _Static_assert() vs C++'s static_assert(). 3437dd6a3dSAndrew Jeffery * 3537dd6a3dSAndrew Jeffery * Can we please have nice things for once. 3637dd6a3dSAndrew Jeffery */ 3737dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 3837dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__) 39c63f63a2SAndrew Jeffery extern "C" { 40c63f63a2SAndrew Jeffery #endif 41c63f63a2SAndrew Jeffery 42b0c1d20aSAndrew Jeffery #include <libpldm/base.h> 43b0c1d20aSAndrew Jeffery #include <libpldm/pldm_types.h> 44c63f63a2SAndrew Jeffery 4566c7723aSAndrew Jeffery #include "compiler.h" 4666c7723aSAndrew Jeffery 47c63f63a2SAndrew Jeffery #include <assert.h> 48c63f63a2SAndrew Jeffery #include <endian.h> 49c63f63a2SAndrew Jeffery #include <limits.h> 50c63f63a2SAndrew Jeffery #include <stdbool.h> 5166c7723aSAndrew Jeffery #include <stdint.h> 52c63f63a2SAndrew Jeffery #include <string.h> 53c63f63a2SAndrew Jeffery #include <sys/types.h> 54c63f63a2SAndrew Jeffery 552ff8cf89SAndrew Jeffery /* 562ff8cf89SAndrew Jeffery * We can't use static_assert() outside of some other C construct. Deal 572ff8cf89SAndrew Jeffery * with high-level global assertions by burying them in an unused struct 582ff8cf89SAndrew Jeffery * declaration, that has a sole member for compliance with the requirement that 592ff8cf89SAndrew Jeffery * types must have a size. 602ff8cf89SAndrew Jeffery */ 612ff8cf89SAndrew Jeffery static struct { 622ff8cf89SAndrew Jeffery static_assert( 632ff8cf89SAndrew Jeffery INTMAX_MAX != SIZE_MAX, 642ff8cf89SAndrew Jeffery "Extraction and insertion value comparisons may be broken"); 652ff8cf89SAndrew Jeffery static_assert(INTMAX_MIN + INTMAX_MAX <= 0, 662ff8cf89SAndrew Jeffery "Extraction and insertion arithmetic may be broken"); 672ff8cf89SAndrew Jeffery int compliance; 682ff8cf89SAndrew Jeffery } build_assertions __attribute__((unused)); 692ff8cf89SAndrew Jeffery 70c63f63a2SAndrew Jeffery struct pldm_msgbuf { 71062c8762SThu Nguyen uint8_t *cursor; 722ff8cf89SAndrew Jeffery intmax_t remaining; 73c63f63a2SAndrew Jeffery }; 74c63f63a2SAndrew Jeffery 75c63f63a2SAndrew Jeffery /** 76c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 77c63f63a2SAndrew Jeffery * 78c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 79c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 80c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 81c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 82c63f63a2SAndrew Jeffery * 83c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 84c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 85c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 86c63f63a2SAndrew Jeffery */ 87*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 88*76712f69SAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 89*76712f69SAndrew Jeffery size_t len) 90c63f63a2SAndrew Jeffery { 91c63f63a2SAndrew Jeffery if (!ctx || !buf) { 92c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 93c63f63a2SAndrew Jeffery } 94c63f63a2SAndrew Jeffery 952ff8cf89SAndrew Jeffery if ((minsize > len)) { 96c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 97c63f63a2SAndrew Jeffery } 98c63f63a2SAndrew Jeffery 992ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 1002ff8cf89SAndrew Jeffery if (len > INTMAX_MAX) { 1012ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 1022ff8cf89SAndrew Jeffery } 1032ff8cf89SAndrew Jeffery #endif 1042ff8cf89SAndrew Jeffery 10507febdbbSAndrew Jeffery if ((uintptr_t)buf + len < len) { 106c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 107c63f63a2SAndrew Jeffery } 108c63f63a2SAndrew Jeffery 109c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 1102ff8cf89SAndrew Jeffery ctx->remaining = (intmax_t)len; 111c63f63a2SAndrew Jeffery 112c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 113c63f63a2SAndrew Jeffery } 114c63f63a2SAndrew Jeffery 115c63f63a2SAndrew Jeffery /** 116c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 117c63f63a2SAndrew Jeffery * 118c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 119c63f63a2SAndrew Jeffery * 120c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 121c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 122c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 123c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 124c63f63a2SAndrew Jeffery * pointer. 125c63f63a2SAndrew Jeffery */ 126*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 127*76712f69SAndrew Jeffery pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 128c63f63a2SAndrew Jeffery { 129c63f63a2SAndrew Jeffery if (!ctx) { 130c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 131c63f63a2SAndrew Jeffery } 132c63f63a2SAndrew Jeffery 133c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 134c63f63a2SAndrew Jeffery } 135c63f63a2SAndrew Jeffery 136c63f63a2SAndrew Jeffery /** 137db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 138db7b8324SAndrew Jeffery * 139db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 140db7b8324SAndrew Jeffery * 141db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 142db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 143db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 144db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 145db7b8324SAndrew Jeffery * pointer. 146db7b8324SAndrew Jeffery */ 147*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 148*76712f69SAndrew Jeffery pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 149db7b8324SAndrew Jeffery { 150db7b8324SAndrew Jeffery if (!ctx) { 151db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 152db7b8324SAndrew Jeffery } 153db7b8324SAndrew Jeffery 154db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 155db7b8324SAndrew Jeffery } 156db7b8324SAndrew Jeffery 157db7b8324SAndrew Jeffery /** 158c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 159c63f63a2SAndrew Jeffery * 160c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 161c63f63a2SAndrew Jeffery * 162c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 163c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 164c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 165c63f63a2SAndrew Jeffery * bounds of the buffer. 166c63f63a2SAndrew Jeffery */ 167*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 168*76712f69SAndrew Jeffery pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 169c63f63a2SAndrew Jeffery { 170c63f63a2SAndrew Jeffery int valid; 171c63f63a2SAndrew Jeffery 172c63f63a2SAndrew Jeffery if (!ctx) { 173c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 174c63f63a2SAndrew Jeffery } 175c63f63a2SAndrew Jeffery 176c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 177c63f63a2SAndrew Jeffery 178c63f63a2SAndrew Jeffery ctx->cursor = NULL; 179c63f63a2SAndrew Jeffery ctx->remaining = 0; 180c63f63a2SAndrew Jeffery 181c63f63a2SAndrew Jeffery return valid; 182c63f63a2SAndrew Jeffery } 183c63f63a2SAndrew Jeffery 184c63f63a2SAndrew Jeffery /** 185db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 186db7b8324SAndrew Jeffery * has been completely consumed without overflow 187db7b8324SAndrew Jeffery * 188db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 189db7b8324SAndrew Jeffery * 190db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 191db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 192db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 193db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 194db7b8324SAndrew Jeffery */ 195*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 196*76712f69SAndrew Jeffery pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 197db7b8324SAndrew Jeffery { 198db7b8324SAndrew Jeffery int consumed; 199db7b8324SAndrew Jeffery 200db7b8324SAndrew Jeffery if (!ctx) { 201db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 202db7b8324SAndrew Jeffery } 203db7b8324SAndrew Jeffery 204db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 205db7b8324SAndrew Jeffery 206db7b8324SAndrew Jeffery ctx->cursor = NULL; 207db7b8324SAndrew Jeffery ctx->remaining = 0; 208db7b8324SAndrew Jeffery 209db7b8324SAndrew Jeffery return consumed; 210db7b8324SAndrew Jeffery } 211db7b8324SAndrew Jeffery 21266c7723aSAndrew Jeffery /* 21366c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 21466c7723aSAndrew Jeffery * 21566c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 21666c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 21766c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 21866c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 21966c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 22066c7723aSAndrew Jeffery * 22166c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 22266c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 22366c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 22466c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 22566c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 22666c7723aSAndrew Jeffery * 22766c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 22866c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 22966c7723aSAndrew Jeffery * constraints that cause some headaches: 23066c7723aSAndrew Jeffery * 23166c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 23266c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 23366c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 23466c7723aSAndrew Jeffery * 23566c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 23666c7723aSAndrew Jeffery * advantage of gtest. 23766c7723aSAndrew Jeffery * 23866c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 23966c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 24066c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 24166c7723aSAndrew Jeffery * 24266c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 24366c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 24466c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 24566c7723aSAndrew Jeffery * 24666c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 24766c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 24866c7723aSAndrew Jeffery * in C++. 24966c7723aSAndrew Jeffery * 25066c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 25166c7723aSAndrew Jeffery * 25266c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 25366c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 25466c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 25566c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 25666c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 25766c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 25866c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 25966c7723aSAndrew Jeffery * 26066c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 26166c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 26266c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 26366c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 26466c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 26566c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 26666c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 26766c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 26866c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 26966c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 27066c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 27166c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 27266c7723aSAndrew Jeffery * template argument per function. 27366c7723aSAndrew Jeffery * 27466c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 27566c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 27666c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 27766c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 27866c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 27966c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 28066c7723aSAndrew Jeffery * 28166c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 28266c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 28366c7723aSAndrew Jeffery * reasons: 28466c7723aSAndrew Jeffery * 28566c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 28666c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 28766c7723aSAndrew Jeffery * 28866c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 28966c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 29066c7723aSAndrew Jeffery */ 29166c7723aSAndrew Jeffery #ifdef __cplusplus 29266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 29366c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 29466c7723aSAndrew Jeffery #else 29566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 29666c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 29766c7723aSAndrew Jeffery #endif 29866c7723aSAndrew Jeffery 299db7b8324SAndrew Jeffery /** 300c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 301c63f63a2SAndrew Jeffery * 302c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 303c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 304c63f63a2SAndrew Jeffery * 305c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 306c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 307c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 308c63f63a2SAndrew Jeffery */ 30966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 31066c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 31166c7723aSAndrew Jeffery dst, ctx, dst) 312*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 31366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 314*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 315c63f63a2SAndrew Jeffery { 316c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 317c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 318c63f63a2SAndrew Jeffery } 319c63f63a2SAndrew Jeffery 3202ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 3212ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3222ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3232ff8cf89SAndrew Jeffery } 32466c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 325c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 326c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 327c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 328c63f63a2SAndrew Jeffery } 329c63f63a2SAndrew Jeffery 33066c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 33166c7723aSAndrew Jeffery 332c63f63a2SAndrew Jeffery ctx->cursor++; 333c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 334c63f63a2SAndrew Jeffery } 335c63f63a2SAndrew Jeffery 33666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 33766c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 33866c7723aSAndrew Jeffery ctx, dst) 339*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 34066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 341*76712f69SAndrew Jeffery pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 342c63f63a2SAndrew Jeffery { 343c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 344c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 345c63f63a2SAndrew Jeffery } 346c63f63a2SAndrew Jeffery 3472ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 3482ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3492ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3502ff8cf89SAndrew Jeffery } 35166c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 352c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 353c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 354c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 355c63f63a2SAndrew Jeffery } 356c63f63a2SAndrew Jeffery 35766c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 358c63f63a2SAndrew Jeffery ctx->cursor++; 359c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 360c63f63a2SAndrew Jeffery } 361c63f63a2SAndrew Jeffery 36266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 36366c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 36466c7723aSAndrew Jeffery dst, ctx, dst) 365*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 36666c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 367*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst) 368c63f63a2SAndrew Jeffery { 369c63f63a2SAndrew Jeffery uint16_t ldst; 370c63f63a2SAndrew Jeffery 371c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 372c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 373c63f63a2SAndrew Jeffery } 374c63f63a2SAndrew Jeffery 3752ff8cf89SAndrew Jeffery // Check for underflow while tracking the magnitude of the buffer overflow 3762ff8cf89SAndrew Jeffery static_assert( 3772ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 3782ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 3792ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 3802ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 3812ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3822ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3832ff8cf89SAndrew Jeffery } 3842ff8cf89SAndrew Jeffery 385c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 386c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 387c63f63a2SAndrew Jeffery // we've overflowed. 388c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 389c63f63a2SAndrew Jeffery 390c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 391c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 392c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 393c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 394c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 395c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 396c63f63a2SAndrew Jeffery } 397c63f63a2SAndrew Jeffery 398c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 399c63f63a2SAndrew Jeffery // issues on the target architecture 400c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 401c63f63a2SAndrew Jeffery 402c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 40366c7723aSAndrew Jeffery ldst = le16toh(ldst); 40466c7723aSAndrew Jeffery 40566c7723aSAndrew Jeffery // Allow storing to unaligned 40666c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 40766c7723aSAndrew Jeffery 408c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 409c63f63a2SAndrew Jeffery 410c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 411c63f63a2SAndrew Jeffery } 412c63f63a2SAndrew Jeffery 41366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 41466c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 41566c7723aSAndrew Jeffery dst, ctx, dst) 416*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 41766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 418*76712f69SAndrew Jeffery pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 419c63f63a2SAndrew Jeffery { 420c63f63a2SAndrew Jeffery int16_t ldst; 421c63f63a2SAndrew Jeffery 422c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 423c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 424c63f63a2SAndrew Jeffery } 425c63f63a2SAndrew Jeffery 4262ff8cf89SAndrew Jeffery static_assert( 4272ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4282ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4292ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4302ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4312ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 4322ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 4332ff8cf89SAndrew Jeffery } 434c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 435c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 436c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 437c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 438c63f63a2SAndrew Jeffery } 439c63f63a2SAndrew Jeffery 440c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 441c63f63a2SAndrew Jeffery 44266c7723aSAndrew Jeffery ldst = le16toh(ldst); 44366c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 444c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 445c63f63a2SAndrew Jeffery 446c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 447c63f63a2SAndrew Jeffery } 448c63f63a2SAndrew Jeffery 44966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 45066c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 45166c7723aSAndrew Jeffery dst, ctx, dst) 452*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 45366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 454*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst) 455c63f63a2SAndrew Jeffery { 456c63f63a2SAndrew Jeffery uint32_t ldst; 457c63f63a2SAndrew Jeffery 458c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 459c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 460c63f63a2SAndrew Jeffery } 461c63f63a2SAndrew Jeffery 4622ff8cf89SAndrew Jeffery static_assert( 4632ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4642ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4652ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4662ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4672ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 4682ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 4692ff8cf89SAndrew Jeffery } 470c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 471c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 472c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 473c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 474c63f63a2SAndrew Jeffery } 475c63f63a2SAndrew Jeffery 476c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 477c63f63a2SAndrew Jeffery 47866c7723aSAndrew Jeffery ldst = le32toh(ldst); 47966c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 480c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 481c63f63a2SAndrew Jeffery 482c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 483c63f63a2SAndrew Jeffery } 484c63f63a2SAndrew Jeffery 48566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 48666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 48766c7723aSAndrew Jeffery dst, ctx, dst) 488*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 48966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 490*76712f69SAndrew Jeffery pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 491c63f63a2SAndrew Jeffery { 492c63f63a2SAndrew Jeffery int32_t ldst; 493c63f63a2SAndrew Jeffery 494c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 495c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 496c63f63a2SAndrew Jeffery } 497c63f63a2SAndrew Jeffery 4982ff8cf89SAndrew Jeffery static_assert( 4992ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5002ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5012ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5022ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5032ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 5042ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 5052ff8cf89SAndrew Jeffery } 506c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 507c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 508c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 509c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 510c63f63a2SAndrew Jeffery } 511c63f63a2SAndrew Jeffery 512c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 513c63f63a2SAndrew Jeffery 51466c7723aSAndrew Jeffery ldst = le32toh(ldst); 51566c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 516c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 517c63f63a2SAndrew Jeffery 518c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 519c63f63a2SAndrew Jeffery } 520c63f63a2SAndrew Jeffery 52166c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst) \ 52266c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 52366c7723aSAndrew Jeffery dst, ctx, dst) 524*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 52566c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 526*76712f69SAndrew Jeffery pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst) 527c63f63a2SAndrew Jeffery { 528c63f63a2SAndrew Jeffery uint32_t ldst; 529c63f63a2SAndrew Jeffery 53066c7723aSAndrew Jeffery _Static_assert(sizeof(real32_t) == sizeof(ldst), 53166c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 53266c7723aSAndrew Jeffery 533c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 534c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 535c63f63a2SAndrew Jeffery } 536c63f63a2SAndrew Jeffery 5372ff8cf89SAndrew Jeffery static_assert( 5382ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5392ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5402ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5412ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5422ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 5432ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 5442ff8cf89SAndrew Jeffery } 545c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 546c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 547c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 548c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 549c63f63a2SAndrew Jeffery } 550c63f63a2SAndrew Jeffery 551c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 552c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 55366c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 55466c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 555c63f63a2SAndrew Jeffery 556c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 557c63f63a2SAndrew Jeffery } 558c63f63a2SAndrew Jeffery 55966c7723aSAndrew Jeffery /** 56066c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 56166c7723aSAndrew Jeffery * 56266c7723aSAndrew Jeffery * @param ctx The msgbuf context object 56366c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 56466c7723aSAndrew Jeffery * extracted 56566c7723aSAndrew Jeffery * 56666c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 56766c7723aSAndrew Jeffery */ 568c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 56966c7723aSAndrew Jeffery _Generic((dst), \ 57066c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 57166c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 57266c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 57366c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 57466c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 57566c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 57666c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 57766c7723aSAndrew Jeffery 57866c7723aSAndrew Jeffery /** 57966c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 58066c7723aSAndrew Jeffery * 58166c7723aSAndrew Jeffery * @param ctx The msgbuf context object 58266c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 58366c7723aSAndrew Jeffery * cursor should be extracted 58466c7723aSAndrew Jeffery * 58566c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 58666c7723aSAndrew Jeffery */ 58766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 58866c7723aSAndrew Jeffery _Generic((dst), \ 58966c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 59066c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 59166c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 59266c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 59366c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 59466c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 59566c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 596c63f63a2SAndrew Jeffery 597*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 598*76712f69SAndrew Jeffery pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst, 599*76712f69SAndrew Jeffery size_t count) 600369b121aSAndrew Jeffery { 601369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 602369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 603369b121aSAndrew Jeffery } 604369b121aSAndrew Jeffery 605369b121aSAndrew Jeffery if (!count) { 606369b121aSAndrew Jeffery return PLDM_SUCCESS; 607369b121aSAndrew Jeffery } 608369b121aSAndrew Jeffery 6092ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 6102ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 611369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 612369b121aSAndrew Jeffery } 6132ff8cf89SAndrew Jeffery #endif 614369b121aSAndrew Jeffery 6152ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 6162ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6172ff8cf89SAndrew Jeffery } 6182ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 619369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 620369b121aSAndrew Jeffery if (ctx->remaining < 0) { 621369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 622369b121aSAndrew Jeffery } 623369b121aSAndrew Jeffery 624a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 625a065eccbSAndrew Jeffery ctx->cursor += count; 626369b121aSAndrew Jeffery 627369b121aSAndrew Jeffery return PLDM_SUCCESS; 628369b121aSAndrew Jeffery } 629369b121aSAndrew Jeffery 630369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 63137dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 63237dd6a3dSAndrew Jeffery count) 633369b121aSAndrew Jeffery 634*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 635*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src) 636062c8762SThu Nguyen { 637062c8762SThu Nguyen uint32_t val = htole32(src); 638062c8762SThu Nguyen 639062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 640062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 641062c8762SThu Nguyen } 642062c8762SThu Nguyen 6432ff8cf89SAndrew Jeffery static_assert( 6442ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6452ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 6462ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6472ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 6482ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 6492ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6502ff8cf89SAndrew Jeffery } 651062c8762SThu Nguyen ctx->remaining -= sizeof(src); 652062c8762SThu Nguyen assert(ctx->remaining >= 0); 653062c8762SThu Nguyen if (ctx->remaining < 0) { 654062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 655062c8762SThu Nguyen } 656062c8762SThu Nguyen 657062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 658062c8762SThu Nguyen ctx->cursor += sizeof(src); 659062c8762SThu Nguyen 660062c8762SThu Nguyen return PLDM_SUCCESS; 661062c8762SThu Nguyen } 662062c8762SThu Nguyen 663*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 664*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src) 665062c8762SThu Nguyen { 666062c8762SThu Nguyen uint16_t val = htole16(src); 667062c8762SThu Nguyen 668062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 669062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 670062c8762SThu Nguyen } 671062c8762SThu Nguyen 6722ff8cf89SAndrew Jeffery static_assert( 6732ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6742ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 6752ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6762ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 6772ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 6782ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6792ff8cf89SAndrew Jeffery } 680062c8762SThu Nguyen ctx->remaining -= sizeof(src); 681062c8762SThu Nguyen assert(ctx->remaining >= 0); 682062c8762SThu Nguyen if (ctx->remaining < 0) { 683062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 684062c8762SThu Nguyen } 685062c8762SThu Nguyen 686062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 687062c8762SThu Nguyen ctx->cursor += sizeof(src); 688062c8762SThu Nguyen 689062c8762SThu Nguyen return PLDM_SUCCESS; 690062c8762SThu Nguyen } 691062c8762SThu Nguyen 692*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 693*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src) 694062c8762SThu Nguyen { 695062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 696062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 697062c8762SThu Nguyen } 698062c8762SThu Nguyen 6992ff8cf89SAndrew Jeffery static_assert( 7002ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7012ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7022ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7032ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7042ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7052ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7062ff8cf89SAndrew Jeffery } 707062c8762SThu Nguyen ctx->remaining -= sizeof(src); 708062c8762SThu Nguyen assert(ctx->remaining >= 0); 709062c8762SThu Nguyen if (ctx->remaining < 0) { 710062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 711062c8762SThu Nguyen } 712062c8762SThu Nguyen 713062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 714062c8762SThu Nguyen ctx->cursor += sizeof(src); 715062c8762SThu Nguyen 716062c8762SThu Nguyen return PLDM_SUCCESS; 717062c8762SThu Nguyen } 718062c8762SThu Nguyen 719*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 720*76712f69SAndrew Jeffery pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src) 721062c8762SThu Nguyen { 722062c8762SThu Nguyen int32_t val = htole32(src); 723062c8762SThu Nguyen 724062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 725062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 726062c8762SThu Nguyen } 727062c8762SThu Nguyen 7282ff8cf89SAndrew Jeffery static_assert( 7292ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7302ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7312ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7322ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7332ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7342ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7352ff8cf89SAndrew Jeffery } 736062c8762SThu Nguyen ctx->remaining -= sizeof(src); 737062c8762SThu Nguyen assert(ctx->remaining >= 0); 738062c8762SThu Nguyen if (ctx->remaining < 0) { 739062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 740062c8762SThu Nguyen } 741062c8762SThu Nguyen 742062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 743062c8762SThu Nguyen ctx->cursor += sizeof(src); 744062c8762SThu Nguyen 745062c8762SThu Nguyen return PLDM_SUCCESS; 746062c8762SThu Nguyen } 747062c8762SThu Nguyen 748*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 749*76712f69SAndrew Jeffery pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src) 750062c8762SThu Nguyen { 751062c8762SThu Nguyen int16_t val = htole16(src); 752062c8762SThu Nguyen 753062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 754062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 755062c8762SThu Nguyen } 756062c8762SThu Nguyen 7572ff8cf89SAndrew Jeffery static_assert( 7582ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7592ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7602ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7612ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7622ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7632ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7642ff8cf89SAndrew Jeffery } 765062c8762SThu Nguyen ctx->remaining -= sizeof(src); 766062c8762SThu Nguyen assert(ctx->remaining >= 0); 767062c8762SThu Nguyen if (ctx->remaining < 0) { 768062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 769062c8762SThu Nguyen } 770062c8762SThu Nguyen 771062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 772062c8762SThu Nguyen ctx->cursor += sizeof(src); 773062c8762SThu Nguyen 774062c8762SThu Nguyen return PLDM_SUCCESS; 775062c8762SThu Nguyen } 776062c8762SThu Nguyen 777*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 778*76712f69SAndrew Jeffery pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src) 779062c8762SThu Nguyen { 780062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 781062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 782062c8762SThu Nguyen } 783062c8762SThu Nguyen 7842ff8cf89SAndrew Jeffery static_assert( 7852ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7862ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7872ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7882ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7892ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7902ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7912ff8cf89SAndrew Jeffery } 792062c8762SThu Nguyen ctx->remaining -= sizeof(src); 793062c8762SThu Nguyen assert(ctx->remaining >= 0); 794062c8762SThu Nguyen if (ctx->remaining < 0) { 795062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 796062c8762SThu Nguyen } 797062c8762SThu Nguyen 798062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 799062c8762SThu Nguyen ctx->cursor += sizeof(src); 800062c8762SThu Nguyen 801062c8762SThu Nguyen return PLDM_SUCCESS; 802062c8762SThu Nguyen } 803062c8762SThu Nguyen 804062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 80537dd6a3dSAndrew Jeffery _Generic((src), \ 80637dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 80737dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 80837dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 80937dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 81037dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 81137dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 812062c8762SThu Nguyen 813*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 814*76712f69SAndrew Jeffery pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src, 815062c8762SThu Nguyen size_t count) 816062c8762SThu Nguyen { 817062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 818062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 819062c8762SThu Nguyen } 820062c8762SThu Nguyen 821062c8762SThu Nguyen if (!count) { 822062c8762SThu Nguyen return PLDM_SUCCESS; 823062c8762SThu Nguyen } 824062c8762SThu Nguyen 8252ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 8262ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 827062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 828062c8762SThu Nguyen } 8292ff8cf89SAndrew Jeffery #endif 830062c8762SThu Nguyen 8312ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 8322ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 8332ff8cf89SAndrew Jeffery } 8342ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 835062c8762SThu Nguyen assert(ctx->remaining >= 0); 836062c8762SThu Nguyen if (ctx->remaining < 0) { 837062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 838062c8762SThu Nguyen } 839062c8762SThu Nguyen 840a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 841a065eccbSAndrew Jeffery ctx->cursor += count; 842062c8762SThu Nguyen 843062c8762SThu Nguyen return PLDM_SUCCESS; 844062c8762SThu Nguyen } 845062c8762SThu Nguyen 846062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 84737dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 84837dd6a3dSAndrew Jeffery count) 849062c8762SThu Nguyen 850*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 851*76712f69SAndrew Jeffery pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required, 852*76712f69SAndrew Jeffery void **cursor) 853062c8762SThu Nguyen { 854062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 855062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 856062c8762SThu Nguyen } 857062c8762SThu Nguyen 8582ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 8592ff8cf89SAndrew Jeffery if (required > INTMAX_MAX) { 860062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 861062c8762SThu Nguyen } 8622ff8cf89SAndrew Jeffery #endif 863062c8762SThu Nguyen 8642ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)required) { 8652ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 8662ff8cf89SAndrew Jeffery } 8672ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)required; 868062c8762SThu Nguyen assert(ctx->remaining >= 0); 869062c8762SThu Nguyen if (ctx->remaining < 0) { 870062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 871062c8762SThu Nguyen } 872062c8762SThu Nguyen 873062c8762SThu Nguyen *cursor = ctx->cursor; 874062c8762SThu Nguyen ctx->cursor += required; 875062c8762SThu Nguyen 876062c8762SThu Nguyen return PLDM_SUCCESS; 877062c8762SThu Nguyen } 878062c8762SThu Nguyen 879*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 880*76712f69SAndrew Jeffery pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len) 881062c8762SThu Nguyen { 882062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 883062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 884062c8762SThu Nguyen } 885062c8762SThu Nguyen 886062c8762SThu Nguyen assert(ctx->remaining >= 0); 887062c8762SThu Nguyen if (ctx->remaining < 0) { 888062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 889062c8762SThu Nguyen } 890062c8762SThu Nguyen 891062c8762SThu Nguyen *cursor = ctx->cursor; 892062c8762SThu Nguyen ctx->cursor += ctx->remaining; 893062c8762SThu Nguyen *len = ctx->remaining; 894062c8762SThu Nguyen ctx->remaining = 0; 895062c8762SThu Nguyen 896062c8762SThu Nguyen return PLDM_SUCCESS; 897062c8762SThu Nguyen } 898909bf7c2SVarsha Kaverappa 899909bf7c2SVarsha Kaverappa /** 900909bf7c2SVarsha Kaverappa * @brief pldm_msgbuf copy data between two msg buffers 901909bf7c2SVarsha Kaverappa * 902909bf7c2SVarsha Kaverappa * @param[inout] src - pldm_msgbuf for source from where value should be copied 903909bf7c2SVarsha Kaverappa * @param[inout] dst - destination of copy from source 904909bf7c2SVarsha Kaverappa * @param[in] size - size of data to be copied 905909bf7c2SVarsha Kaverappa * @param[in] description - description of data copied 906909bf7c2SVarsha Kaverappa * 907909bf7c2SVarsha Kaverappa * @return PLDM_SUCCESS if buffer accesses were in-bounds, 908909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_LENGTH otherwise. 909909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_DATA if input is invalid 910909bf7c2SVarsha Kaverappa */ 911909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name) \ 912909bf7c2SVarsha Kaverappa pldm__msgbuf_copy(dst, src, sizeof(type), #name) 913*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 914909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 915*76712f69SAndrew Jeffery pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size, 916909bf7c2SVarsha Kaverappa const char *description) 917909bf7c2SVarsha Kaverappa { 918909bf7c2SVarsha Kaverappa if (!src || !src->cursor || !dst || !dst->cursor || !description) { 919909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_DATA; 920909bf7c2SVarsha Kaverappa } 921909bf7c2SVarsha Kaverappa 922909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX 923909bf7c2SVarsha Kaverappa if (size > INTMAX_MAX) { 924909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 925909bf7c2SVarsha Kaverappa } 926909bf7c2SVarsha Kaverappa #endif 927909bf7c2SVarsha Kaverappa 928909bf7c2SVarsha Kaverappa if (src->remaining < INTMAX_MIN + (intmax_t)size) { 929909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 930909bf7c2SVarsha Kaverappa } 931909bf7c2SVarsha Kaverappa 932909bf7c2SVarsha Kaverappa if (dst->remaining < INTMAX_MIN + (intmax_t)size) { 933909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 934909bf7c2SVarsha Kaverappa } 935909bf7c2SVarsha Kaverappa 936909bf7c2SVarsha Kaverappa src->remaining -= (intmax_t)size; 937909bf7c2SVarsha Kaverappa assert(src->remaining >= 0); 938909bf7c2SVarsha Kaverappa if (src->remaining < 0) { 939909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 940909bf7c2SVarsha Kaverappa } 941909bf7c2SVarsha Kaverappa 942909bf7c2SVarsha Kaverappa dst->remaining -= (intmax_t)size; 943909bf7c2SVarsha Kaverappa assert(dst->remaining >= 0); 944909bf7c2SVarsha Kaverappa if (dst->remaining < 0) { 945909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 946909bf7c2SVarsha Kaverappa } 947909bf7c2SVarsha Kaverappa 948909bf7c2SVarsha Kaverappa memcpy(dst->cursor, src->cursor, size); 949909bf7c2SVarsha Kaverappa src->cursor += size; 950909bf7c2SVarsha Kaverappa dst->cursor += size; 951909bf7c2SVarsha Kaverappa 952909bf7c2SVarsha Kaverappa return PLDM_SUCCESS; 953909bf7c2SVarsha Kaverappa } 954c63f63a2SAndrew Jeffery #ifdef __cplusplus 955c63f63a2SAndrew Jeffery } 956c63f63a2SAndrew Jeffery #endif 957c63f63a2SAndrew Jeffery 95866c7723aSAndrew Jeffery #ifdef __cplusplus 95966c7723aSAndrew Jeffery #include <type_traits> 96066c7723aSAndrew Jeffery 96166c7723aSAndrew Jeffery template <typename T> 96266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 96366c7723aSAndrew Jeffery void *buf) 96466c7723aSAndrew Jeffery { 96566c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 96666c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 96766c7723aSAndrew Jeffery } 96866c7723aSAndrew Jeffery 96966c7723aSAndrew Jeffery template <typename T> 97066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 97166c7723aSAndrew Jeffery void *buf) 97266c7723aSAndrew Jeffery { 97366c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 97466c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 97566c7723aSAndrew Jeffery } 97666c7723aSAndrew Jeffery 97766c7723aSAndrew Jeffery template <typename T> 97866c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 97966c7723aSAndrew Jeffery void *buf) 98066c7723aSAndrew Jeffery { 98166c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 98266c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 98366c7723aSAndrew Jeffery } 98466c7723aSAndrew Jeffery 98566c7723aSAndrew Jeffery template <typename T> 98666c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 98766c7723aSAndrew Jeffery void *buf) 98866c7723aSAndrew Jeffery { 98966c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 99066c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 99166c7723aSAndrew Jeffery } 99266c7723aSAndrew Jeffery 99366c7723aSAndrew Jeffery template <typename T> 99466c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 99566c7723aSAndrew Jeffery void *buf) 99666c7723aSAndrew Jeffery { 99766c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 99866c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 99966c7723aSAndrew Jeffery } 100066c7723aSAndrew Jeffery 100166c7723aSAndrew Jeffery template <typename T> 100266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 100366c7723aSAndrew Jeffery void *buf) 100466c7723aSAndrew Jeffery { 100566c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 100666c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 100766c7723aSAndrew Jeffery } 100866c7723aSAndrew Jeffery 100966c7723aSAndrew Jeffery template <typename T> 101066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 101166c7723aSAndrew Jeffery void *buf) 101266c7723aSAndrew Jeffery { 101366c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 101466c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 101566c7723aSAndrew Jeffery } 101666c7723aSAndrew Jeffery #endif 101766c7723aSAndrew Jeffery 1018c63f63a2SAndrew Jeffery #endif /* BUF_H */ 1019