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 */ 8707febdbbSAndrew Jeffery static inline int pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, 8807febdbbSAndrew Jeffery const void *buf, size_t len) 89c63f63a2SAndrew Jeffery { 90c63f63a2SAndrew Jeffery if (!ctx || !buf) { 91c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 92c63f63a2SAndrew Jeffery } 93c63f63a2SAndrew Jeffery 942ff8cf89SAndrew Jeffery if ((minsize > len)) { 95c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 96c63f63a2SAndrew Jeffery } 97c63f63a2SAndrew Jeffery 982ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 992ff8cf89SAndrew Jeffery if (len > INTMAX_MAX) { 1002ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 1012ff8cf89SAndrew Jeffery } 1022ff8cf89SAndrew Jeffery #endif 1032ff8cf89SAndrew Jeffery 10407febdbbSAndrew Jeffery if ((uintptr_t)buf + len < len) { 105c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 106c63f63a2SAndrew Jeffery } 107c63f63a2SAndrew Jeffery 108c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 1092ff8cf89SAndrew Jeffery ctx->remaining = (intmax_t)len; 110c63f63a2SAndrew Jeffery 111c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 112c63f63a2SAndrew Jeffery } 113c63f63a2SAndrew Jeffery 114c63f63a2SAndrew Jeffery /** 115c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 116c63f63a2SAndrew Jeffery * 117c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 118c63f63a2SAndrew Jeffery * 119c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 120c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 121c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 122c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 123c63f63a2SAndrew Jeffery * pointer. 124c63f63a2SAndrew Jeffery */ 125c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 126c63f63a2SAndrew Jeffery { 127c63f63a2SAndrew Jeffery if (!ctx) { 128c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 129c63f63a2SAndrew Jeffery } 130c63f63a2SAndrew Jeffery 131c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 132c63f63a2SAndrew Jeffery } 133c63f63a2SAndrew Jeffery 134c63f63a2SAndrew Jeffery /** 135db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 136db7b8324SAndrew Jeffery * 137db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 138db7b8324SAndrew Jeffery * 139db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 140db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 141db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 142db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 143db7b8324SAndrew Jeffery * pointer. 144db7b8324SAndrew Jeffery */ 145db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 146db7b8324SAndrew Jeffery { 147db7b8324SAndrew Jeffery if (!ctx) { 148db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 149db7b8324SAndrew Jeffery } 150db7b8324SAndrew Jeffery 151db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 152db7b8324SAndrew Jeffery } 153db7b8324SAndrew Jeffery 154db7b8324SAndrew Jeffery /** 155c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 156c63f63a2SAndrew Jeffery * 157c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 158c63f63a2SAndrew Jeffery * 159c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 160c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 161c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 162c63f63a2SAndrew Jeffery * bounds of the buffer. 163c63f63a2SAndrew Jeffery */ 164c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 165c63f63a2SAndrew Jeffery { 166c63f63a2SAndrew Jeffery int valid; 167c63f63a2SAndrew Jeffery 168c63f63a2SAndrew Jeffery if (!ctx) { 169c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 170c63f63a2SAndrew Jeffery } 171c63f63a2SAndrew Jeffery 172c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 173c63f63a2SAndrew Jeffery 174c63f63a2SAndrew Jeffery ctx->cursor = NULL; 175c63f63a2SAndrew Jeffery ctx->remaining = 0; 176c63f63a2SAndrew Jeffery 177c63f63a2SAndrew Jeffery return valid; 178c63f63a2SAndrew Jeffery } 179c63f63a2SAndrew Jeffery 180c63f63a2SAndrew Jeffery /** 181db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 182db7b8324SAndrew Jeffery * has been completely consumed without overflow 183db7b8324SAndrew Jeffery * 184db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 185db7b8324SAndrew Jeffery * 186db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 187db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 188db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 189db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 190db7b8324SAndrew Jeffery */ 191db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 192db7b8324SAndrew Jeffery { 193db7b8324SAndrew Jeffery int consumed; 194db7b8324SAndrew Jeffery 195db7b8324SAndrew Jeffery if (!ctx) { 196db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 197db7b8324SAndrew Jeffery } 198db7b8324SAndrew Jeffery 199db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 200db7b8324SAndrew Jeffery 201db7b8324SAndrew Jeffery ctx->cursor = NULL; 202db7b8324SAndrew Jeffery ctx->remaining = 0; 203db7b8324SAndrew Jeffery 204db7b8324SAndrew Jeffery return consumed; 205db7b8324SAndrew Jeffery } 206db7b8324SAndrew Jeffery 20766c7723aSAndrew Jeffery /* 20866c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 20966c7723aSAndrew Jeffery * 21066c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 21166c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 21266c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 21366c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 21466c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 21566c7723aSAndrew Jeffery * 21666c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 21766c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 21866c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 21966c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 22066c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 22166c7723aSAndrew Jeffery * 22266c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 22366c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 22466c7723aSAndrew Jeffery * constraints that cause some headaches: 22566c7723aSAndrew Jeffery * 22666c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 22766c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 22866c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 22966c7723aSAndrew Jeffery * 23066c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 23166c7723aSAndrew Jeffery * advantage of gtest. 23266c7723aSAndrew Jeffery * 23366c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 23466c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 23566c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 23666c7723aSAndrew Jeffery * 23766c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 23866c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 23966c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 24066c7723aSAndrew Jeffery * 24166c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 24266c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 24366c7723aSAndrew Jeffery * in C++. 24466c7723aSAndrew Jeffery * 24566c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 24666c7723aSAndrew Jeffery * 24766c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 24866c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 24966c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 25066c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 25166c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 25266c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 25366c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 25466c7723aSAndrew Jeffery * 25566c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 25666c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 25766c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 25866c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 25966c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 26066c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 26166c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 26266c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 26366c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 26466c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 26566c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 26666c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 26766c7723aSAndrew Jeffery * template argument per function. 26866c7723aSAndrew Jeffery * 26966c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 27066c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 27166c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 27266c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 27366c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 27466c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 27566c7723aSAndrew Jeffery * 27666c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 27766c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 27866c7723aSAndrew Jeffery * reasons: 27966c7723aSAndrew Jeffery * 28066c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 28166c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 28266c7723aSAndrew Jeffery * 28366c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 28466c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 28566c7723aSAndrew Jeffery */ 28666c7723aSAndrew Jeffery #ifdef __cplusplus 28766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 28866c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 28966c7723aSAndrew Jeffery #else 29066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 29166c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 29266c7723aSAndrew Jeffery #endif 29366c7723aSAndrew Jeffery 294db7b8324SAndrew Jeffery /** 295c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 296c63f63a2SAndrew Jeffery * 297c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 298c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 299c63f63a2SAndrew Jeffery * 300c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 301c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 302c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 303c63f63a2SAndrew Jeffery */ 30466c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 30566c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 30666c7723aSAndrew Jeffery dst, ctx, dst) 30766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 30866c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 309c63f63a2SAndrew Jeffery { 310c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 311c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 312c63f63a2SAndrew Jeffery } 313c63f63a2SAndrew Jeffery 3142ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 3152ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3162ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3172ff8cf89SAndrew Jeffery } 31866c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 319c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 320c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 321c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 322c63f63a2SAndrew Jeffery } 323c63f63a2SAndrew Jeffery 32466c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 32566c7723aSAndrew Jeffery 326c63f63a2SAndrew Jeffery ctx->cursor++; 327c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 328c63f63a2SAndrew Jeffery } 329c63f63a2SAndrew Jeffery 33066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 33166c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 33266c7723aSAndrew Jeffery ctx, dst) 33366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 33466c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 335c63f63a2SAndrew Jeffery { 336c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 337c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 338c63f63a2SAndrew Jeffery } 339c63f63a2SAndrew Jeffery 3402ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 3412ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3422ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3432ff8cf89SAndrew Jeffery } 34466c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 345c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 346c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 347c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 348c63f63a2SAndrew Jeffery } 349c63f63a2SAndrew Jeffery 35066c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 351c63f63a2SAndrew Jeffery ctx->cursor++; 352c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 353c63f63a2SAndrew Jeffery } 354c63f63a2SAndrew Jeffery 35566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 35666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 35766c7723aSAndrew Jeffery dst, ctx, dst) 35866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 35966c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 36066c7723aSAndrew Jeffery void *dst) 361c63f63a2SAndrew Jeffery { 362c63f63a2SAndrew Jeffery uint16_t ldst; 363c63f63a2SAndrew Jeffery 364c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 365c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 366c63f63a2SAndrew Jeffery } 367c63f63a2SAndrew Jeffery 3682ff8cf89SAndrew Jeffery // Check for underflow while tracking the magnitude of the buffer overflow 3692ff8cf89SAndrew Jeffery static_assert( 3702ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 3712ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 3722ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 3732ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 3742ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 3752ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 3762ff8cf89SAndrew Jeffery } 3772ff8cf89SAndrew Jeffery 378c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 379c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 380c63f63a2SAndrew Jeffery // we've overflowed. 381c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 382c63f63a2SAndrew Jeffery 383c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 384c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 385c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 386c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 387c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 388c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 389c63f63a2SAndrew Jeffery } 390c63f63a2SAndrew Jeffery 391c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 392c63f63a2SAndrew Jeffery // issues on the target architecture 393c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 394c63f63a2SAndrew Jeffery 395c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 39666c7723aSAndrew Jeffery ldst = le16toh(ldst); 39766c7723aSAndrew Jeffery 39866c7723aSAndrew Jeffery // Allow storing to unaligned 39966c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 40066c7723aSAndrew Jeffery 401c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 402c63f63a2SAndrew Jeffery 403c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 404c63f63a2SAndrew Jeffery } 405c63f63a2SAndrew Jeffery 40666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 40766c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 40866c7723aSAndrew Jeffery dst, ctx, dst) 40966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 41066c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 411c63f63a2SAndrew Jeffery { 412c63f63a2SAndrew Jeffery int16_t ldst; 413c63f63a2SAndrew Jeffery 414c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 415c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 416c63f63a2SAndrew Jeffery } 417c63f63a2SAndrew Jeffery 4182ff8cf89SAndrew Jeffery static_assert( 4192ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4202ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4212ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4222ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4232ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 4242ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 4252ff8cf89SAndrew Jeffery } 426c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 427c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 428c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 429c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 430c63f63a2SAndrew Jeffery } 431c63f63a2SAndrew Jeffery 432c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 433c63f63a2SAndrew Jeffery 43466c7723aSAndrew Jeffery ldst = le16toh(ldst); 43566c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 436c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 437c63f63a2SAndrew Jeffery 438c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 439c63f63a2SAndrew Jeffery } 440c63f63a2SAndrew Jeffery 44166c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 44266c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 44366c7723aSAndrew Jeffery dst, ctx, dst) 44466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 44566c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 44666c7723aSAndrew Jeffery void *dst) 447c63f63a2SAndrew Jeffery { 448c63f63a2SAndrew Jeffery uint32_t ldst; 449c63f63a2SAndrew Jeffery 450c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 451c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 452c63f63a2SAndrew Jeffery } 453c63f63a2SAndrew Jeffery 4542ff8cf89SAndrew Jeffery static_assert( 4552ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4562ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4572ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4582ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4592ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 4602ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 4612ff8cf89SAndrew Jeffery } 462c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 463c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 464c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 465c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 466c63f63a2SAndrew Jeffery } 467c63f63a2SAndrew Jeffery 468c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 469c63f63a2SAndrew Jeffery 47066c7723aSAndrew Jeffery ldst = le32toh(ldst); 47166c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 472c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 473c63f63a2SAndrew Jeffery 474c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 475c63f63a2SAndrew Jeffery } 476c63f63a2SAndrew Jeffery 47766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 47866c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 47966c7723aSAndrew Jeffery dst, ctx, dst) 48066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 48166c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 482c63f63a2SAndrew Jeffery { 483c63f63a2SAndrew Jeffery int32_t ldst; 484c63f63a2SAndrew Jeffery 485c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 486c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 487c63f63a2SAndrew Jeffery } 488c63f63a2SAndrew Jeffery 4892ff8cf89SAndrew Jeffery static_assert( 4902ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4912ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4922ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4932ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4942ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 4952ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 4962ff8cf89SAndrew Jeffery } 497c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 498c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 499c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 500c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 501c63f63a2SAndrew Jeffery } 502c63f63a2SAndrew Jeffery 503c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 504c63f63a2SAndrew Jeffery 50566c7723aSAndrew Jeffery ldst = le32toh(ldst); 50666c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 507c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 508c63f63a2SAndrew Jeffery 509c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 510c63f63a2SAndrew Jeffery } 511c63f63a2SAndrew Jeffery 51266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst) \ 51366c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 51466c7723aSAndrew Jeffery dst, ctx, dst) 51566c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 51666c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, 51766c7723aSAndrew Jeffery void *dst) 518c63f63a2SAndrew Jeffery { 519c63f63a2SAndrew Jeffery uint32_t ldst; 520c63f63a2SAndrew Jeffery 52166c7723aSAndrew Jeffery _Static_assert(sizeof(real32_t) == sizeof(ldst), 52266c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 52366c7723aSAndrew Jeffery 524c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 525c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 526c63f63a2SAndrew Jeffery } 527c63f63a2SAndrew Jeffery 5282ff8cf89SAndrew Jeffery static_assert( 5292ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5302ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5312ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5322ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5332ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 5342ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 5352ff8cf89SAndrew Jeffery } 536c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 537c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 538c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 539c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 540c63f63a2SAndrew Jeffery } 541c63f63a2SAndrew Jeffery 542c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 543c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 54466c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 54566c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 546c63f63a2SAndrew Jeffery 547c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 548c63f63a2SAndrew Jeffery } 549c63f63a2SAndrew Jeffery 55066c7723aSAndrew Jeffery /** 55166c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 55266c7723aSAndrew Jeffery * 55366c7723aSAndrew Jeffery * @param ctx The msgbuf context object 55466c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 55566c7723aSAndrew Jeffery * extracted 55666c7723aSAndrew Jeffery * 55766c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 55866c7723aSAndrew Jeffery */ 559c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 56066c7723aSAndrew Jeffery _Generic((dst), \ 56166c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 56266c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 56366c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 56466c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 56566c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 56666c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 56766c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 56866c7723aSAndrew Jeffery 56966c7723aSAndrew Jeffery /** 57066c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 57166c7723aSAndrew Jeffery * 57266c7723aSAndrew Jeffery * @param ctx The msgbuf context object 57366c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 57466c7723aSAndrew Jeffery * cursor should be extracted 57566c7723aSAndrew Jeffery * 57666c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 57766c7723aSAndrew Jeffery */ 57866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 57966c7723aSAndrew Jeffery _Generic((dst), \ 58066c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 58166c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 58266c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 58366c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 58466c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 58566c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 58666c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 587c63f63a2SAndrew Jeffery 588369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 589369b121aSAndrew Jeffery uint8_t *dst, size_t count) 590369b121aSAndrew Jeffery { 591369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 592369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 593369b121aSAndrew Jeffery } 594369b121aSAndrew Jeffery 595369b121aSAndrew Jeffery if (!count) { 596369b121aSAndrew Jeffery return PLDM_SUCCESS; 597369b121aSAndrew Jeffery } 598369b121aSAndrew Jeffery 5992ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 6002ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 601369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 602369b121aSAndrew Jeffery } 6032ff8cf89SAndrew Jeffery #endif 604369b121aSAndrew Jeffery 6052ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 6062ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6072ff8cf89SAndrew Jeffery } 6082ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 609369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 610369b121aSAndrew Jeffery if (ctx->remaining < 0) { 611369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 612369b121aSAndrew Jeffery } 613369b121aSAndrew Jeffery 614a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 615a065eccbSAndrew Jeffery ctx->cursor += count; 616369b121aSAndrew Jeffery 617369b121aSAndrew Jeffery return PLDM_SUCCESS; 618369b121aSAndrew Jeffery } 619369b121aSAndrew Jeffery 620369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 62137dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 62237dd6a3dSAndrew Jeffery count) 623369b121aSAndrew Jeffery 624062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, 625062c8762SThu Nguyen const uint32_t src) 626062c8762SThu Nguyen { 627062c8762SThu Nguyen uint32_t val = htole32(src); 628062c8762SThu Nguyen 629062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 630062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 631062c8762SThu Nguyen } 632062c8762SThu Nguyen 6332ff8cf89SAndrew Jeffery static_assert( 6342ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6352ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 6362ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6372ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 6382ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 6392ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6402ff8cf89SAndrew Jeffery } 641062c8762SThu Nguyen ctx->remaining -= sizeof(src); 642062c8762SThu Nguyen assert(ctx->remaining >= 0); 643062c8762SThu Nguyen if (ctx->remaining < 0) { 644062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 645062c8762SThu Nguyen } 646062c8762SThu Nguyen 647062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 648062c8762SThu Nguyen ctx->cursor += sizeof(src); 649062c8762SThu Nguyen 650062c8762SThu Nguyen return PLDM_SUCCESS; 651062c8762SThu Nguyen } 652062c8762SThu Nguyen 653062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, 654062c8762SThu Nguyen const uint16_t src) 655062c8762SThu Nguyen { 656062c8762SThu Nguyen uint16_t val = htole16(src); 657062c8762SThu Nguyen 658062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 659062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 660062c8762SThu Nguyen } 661062c8762SThu Nguyen 6622ff8cf89SAndrew Jeffery static_assert( 6632ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6642ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 6652ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6662ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 6672ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 6682ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6692ff8cf89SAndrew Jeffery } 670062c8762SThu Nguyen ctx->remaining -= sizeof(src); 671062c8762SThu Nguyen assert(ctx->remaining >= 0); 672062c8762SThu Nguyen if (ctx->remaining < 0) { 673062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 674062c8762SThu Nguyen } 675062c8762SThu Nguyen 676062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 677062c8762SThu Nguyen ctx->cursor += sizeof(src); 678062c8762SThu Nguyen 679062c8762SThu Nguyen return PLDM_SUCCESS; 680062c8762SThu Nguyen } 681062c8762SThu Nguyen 682062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, 683062c8762SThu Nguyen const uint8_t src) 684062c8762SThu Nguyen { 685062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 686062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 687062c8762SThu Nguyen } 688062c8762SThu Nguyen 6892ff8cf89SAndrew Jeffery static_assert( 6902ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6912ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 6922ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6932ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 6942ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 6952ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 6962ff8cf89SAndrew Jeffery } 697062c8762SThu Nguyen ctx->remaining -= sizeof(src); 698062c8762SThu Nguyen assert(ctx->remaining >= 0); 699062c8762SThu Nguyen if (ctx->remaining < 0) { 700062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 701062c8762SThu Nguyen } 702062c8762SThu Nguyen 703062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 704062c8762SThu Nguyen ctx->cursor += sizeof(src); 705062c8762SThu Nguyen 706062c8762SThu Nguyen return PLDM_SUCCESS; 707062c8762SThu Nguyen } 708062c8762SThu Nguyen 709062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, 710062c8762SThu Nguyen const int32_t src) 711062c8762SThu Nguyen { 712062c8762SThu Nguyen int32_t val = htole32(src); 713062c8762SThu Nguyen 714062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 715062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 716062c8762SThu Nguyen } 717062c8762SThu Nguyen 7182ff8cf89SAndrew Jeffery static_assert( 7192ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7202ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7212ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7222ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7232ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7242ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7252ff8cf89SAndrew Jeffery } 726062c8762SThu Nguyen ctx->remaining -= sizeof(src); 727062c8762SThu Nguyen assert(ctx->remaining >= 0); 728062c8762SThu Nguyen if (ctx->remaining < 0) { 729062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 730062c8762SThu Nguyen } 731062c8762SThu Nguyen 732062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 733062c8762SThu Nguyen ctx->cursor += sizeof(src); 734062c8762SThu Nguyen 735062c8762SThu Nguyen return PLDM_SUCCESS; 736062c8762SThu Nguyen } 737062c8762SThu Nguyen 738062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, 739062c8762SThu Nguyen const int16_t src) 740062c8762SThu Nguyen { 741062c8762SThu Nguyen int16_t val = htole16(src); 742062c8762SThu Nguyen 743062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 744062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 745062c8762SThu Nguyen } 746062c8762SThu Nguyen 7472ff8cf89SAndrew Jeffery static_assert( 7482ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7492ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7502ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7512ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7522ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7532ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7542ff8cf89SAndrew Jeffery } 755062c8762SThu Nguyen ctx->remaining -= sizeof(src); 756062c8762SThu Nguyen assert(ctx->remaining >= 0); 757062c8762SThu Nguyen if (ctx->remaining < 0) { 758062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 759062c8762SThu Nguyen } 760062c8762SThu Nguyen 761062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 762062c8762SThu Nguyen ctx->cursor += sizeof(src); 763062c8762SThu Nguyen 764062c8762SThu Nguyen return PLDM_SUCCESS; 765062c8762SThu Nguyen } 766062c8762SThu Nguyen 767062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, 768062c8762SThu Nguyen const int8_t src) 769062c8762SThu Nguyen { 770062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 771062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 772062c8762SThu Nguyen } 773062c8762SThu Nguyen 7742ff8cf89SAndrew Jeffery static_assert( 7752ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7762ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7772ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7782ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7792ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 7802ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 7812ff8cf89SAndrew Jeffery } 782062c8762SThu Nguyen ctx->remaining -= sizeof(src); 783062c8762SThu Nguyen assert(ctx->remaining >= 0); 784062c8762SThu Nguyen if (ctx->remaining < 0) { 785062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 786062c8762SThu Nguyen } 787062c8762SThu Nguyen 788062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 789062c8762SThu Nguyen ctx->cursor += sizeof(src); 790062c8762SThu Nguyen 791062c8762SThu Nguyen return PLDM_SUCCESS; 792062c8762SThu Nguyen } 793062c8762SThu Nguyen 794062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 79537dd6a3dSAndrew Jeffery _Generic((src), \ 79637dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 79737dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 79837dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 79937dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 80037dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 80137dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 802062c8762SThu Nguyen 803062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, 804062c8762SThu Nguyen const uint8_t *src, 805062c8762SThu Nguyen size_t count) 806062c8762SThu Nguyen { 807062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 808062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 809062c8762SThu Nguyen } 810062c8762SThu Nguyen 811062c8762SThu Nguyen if (!count) { 812062c8762SThu Nguyen return PLDM_SUCCESS; 813062c8762SThu Nguyen } 814062c8762SThu Nguyen 8152ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 8162ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 817062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 818062c8762SThu Nguyen } 8192ff8cf89SAndrew Jeffery #endif 820062c8762SThu Nguyen 8212ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 8222ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 8232ff8cf89SAndrew Jeffery } 8242ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 825062c8762SThu Nguyen assert(ctx->remaining >= 0); 826062c8762SThu Nguyen if (ctx->remaining < 0) { 827062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 828062c8762SThu Nguyen } 829062c8762SThu Nguyen 830a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 831a065eccbSAndrew Jeffery ctx->cursor += count; 832062c8762SThu Nguyen 833062c8762SThu Nguyen return PLDM_SUCCESS; 834062c8762SThu Nguyen } 835062c8762SThu Nguyen 836062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 83737dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 83837dd6a3dSAndrew Jeffery count) 839062c8762SThu Nguyen 840062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, 841062c8762SThu Nguyen size_t required, void **cursor) 842062c8762SThu Nguyen { 843062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 844062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 845062c8762SThu Nguyen } 846062c8762SThu Nguyen 8472ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 8482ff8cf89SAndrew Jeffery if (required > INTMAX_MAX) { 849062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 850062c8762SThu Nguyen } 8512ff8cf89SAndrew Jeffery #endif 852062c8762SThu Nguyen 8532ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)required) { 8542ff8cf89SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 8552ff8cf89SAndrew Jeffery } 8562ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)required; 857062c8762SThu Nguyen assert(ctx->remaining >= 0); 858062c8762SThu Nguyen if (ctx->remaining < 0) { 859062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 860062c8762SThu Nguyen } 861062c8762SThu Nguyen 862062c8762SThu Nguyen *cursor = ctx->cursor; 863062c8762SThu Nguyen ctx->cursor += required; 864062c8762SThu Nguyen 865062c8762SThu Nguyen return PLDM_SUCCESS; 866062c8762SThu Nguyen } 867062c8762SThu Nguyen 868062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, 869062c8762SThu Nguyen void **cursor, size_t *len) 870062c8762SThu Nguyen { 871062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 872062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 873062c8762SThu Nguyen } 874062c8762SThu Nguyen 875062c8762SThu Nguyen assert(ctx->remaining >= 0); 876062c8762SThu Nguyen if (ctx->remaining < 0) { 877062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 878062c8762SThu Nguyen } 879062c8762SThu Nguyen 880062c8762SThu Nguyen *cursor = ctx->cursor; 881062c8762SThu Nguyen ctx->cursor += ctx->remaining; 882062c8762SThu Nguyen *len = ctx->remaining; 883062c8762SThu Nguyen ctx->remaining = 0; 884062c8762SThu Nguyen 885062c8762SThu Nguyen return PLDM_SUCCESS; 886062c8762SThu Nguyen } 887*909bf7c2SVarsha Kaverappa 888*909bf7c2SVarsha Kaverappa /** 889*909bf7c2SVarsha Kaverappa * @brief pldm_msgbuf copy data between two msg buffers 890*909bf7c2SVarsha Kaverappa * 891*909bf7c2SVarsha Kaverappa * @param[inout] src - pldm_msgbuf for source from where value should be copied 892*909bf7c2SVarsha Kaverappa * @param[inout] dst - destination of copy from source 893*909bf7c2SVarsha Kaverappa * @param[in] size - size of data to be copied 894*909bf7c2SVarsha Kaverappa * @param[in] description - description of data copied 895*909bf7c2SVarsha Kaverappa * 896*909bf7c2SVarsha Kaverappa * @return PLDM_SUCCESS if buffer accesses were in-bounds, 897*909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_LENGTH otherwise. 898*909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_DATA if input is invalid 899*909bf7c2SVarsha Kaverappa */ 900*909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name) \ 901*909bf7c2SVarsha Kaverappa pldm__msgbuf_copy(dst, src, sizeof(type), #name) 902*909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 903*909bf7c2SVarsha Kaverappa static inline int pldm__msgbuf_copy(struct pldm_msgbuf *dst, 904*909bf7c2SVarsha Kaverappa struct pldm_msgbuf *src, size_t size, 905*909bf7c2SVarsha Kaverappa const char *description) 906*909bf7c2SVarsha Kaverappa { 907*909bf7c2SVarsha Kaverappa if (!src || !src->cursor || !dst || !dst->cursor || !description) { 908*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_DATA; 909*909bf7c2SVarsha Kaverappa } 910*909bf7c2SVarsha Kaverappa 911*909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX 912*909bf7c2SVarsha Kaverappa if (size > INTMAX_MAX) { 913*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 914*909bf7c2SVarsha Kaverappa } 915*909bf7c2SVarsha Kaverappa #endif 916*909bf7c2SVarsha Kaverappa 917*909bf7c2SVarsha Kaverappa if (src->remaining < INTMAX_MIN + (intmax_t)size) { 918*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 919*909bf7c2SVarsha Kaverappa } 920*909bf7c2SVarsha Kaverappa 921*909bf7c2SVarsha Kaverappa if (dst->remaining < INTMAX_MIN + (intmax_t)size) { 922*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 923*909bf7c2SVarsha Kaverappa } 924*909bf7c2SVarsha Kaverappa 925*909bf7c2SVarsha Kaverappa src->remaining -= (intmax_t)size; 926*909bf7c2SVarsha Kaverappa assert(src->remaining >= 0); 927*909bf7c2SVarsha Kaverappa if (src->remaining < 0) { 928*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 929*909bf7c2SVarsha Kaverappa } 930*909bf7c2SVarsha Kaverappa 931*909bf7c2SVarsha Kaverappa dst->remaining -= (intmax_t)size; 932*909bf7c2SVarsha Kaverappa assert(dst->remaining >= 0); 933*909bf7c2SVarsha Kaverappa if (dst->remaining < 0) { 934*909bf7c2SVarsha Kaverappa return PLDM_ERROR_INVALID_LENGTH; 935*909bf7c2SVarsha Kaverappa } 936*909bf7c2SVarsha Kaverappa 937*909bf7c2SVarsha Kaverappa memcpy(dst->cursor, src->cursor, size); 938*909bf7c2SVarsha Kaverappa src->cursor += size; 939*909bf7c2SVarsha Kaverappa dst->cursor += size; 940*909bf7c2SVarsha Kaverappa 941*909bf7c2SVarsha Kaverappa return PLDM_SUCCESS; 942*909bf7c2SVarsha Kaverappa } 943c63f63a2SAndrew Jeffery #ifdef __cplusplus 944c63f63a2SAndrew Jeffery } 945c63f63a2SAndrew Jeffery #endif 946c63f63a2SAndrew Jeffery 94766c7723aSAndrew Jeffery #ifdef __cplusplus 94866c7723aSAndrew Jeffery #include <type_traits> 94966c7723aSAndrew Jeffery 95066c7723aSAndrew Jeffery template <typename T> 95166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 95266c7723aSAndrew Jeffery void *buf) 95366c7723aSAndrew Jeffery { 95466c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 95566c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 95666c7723aSAndrew Jeffery } 95766c7723aSAndrew Jeffery 95866c7723aSAndrew Jeffery template <typename T> 95966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 96066c7723aSAndrew Jeffery void *buf) 96166c7723aSAndrew Jeffery { 96266c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 96366c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 96466c7723aSAndrew Jeffery } 96566c7723aSAndrew Jeffery 96666c7723aSAndrew Jeffery template <typename T> 96766c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 96866c7723aSAndrew Jeffery void *buf) 96966c7723aSAndrew Jeffery { 97066c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 97166c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 97266c7723aSAndrew Jeffery } 97366c7723aSAndrew Jeffery 97466c7723aSAndrew Jeffery template <typename T> 97566c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 97666c7723aSAndrew Jeffery void *buf) 97766c7723aSAndrew Jeffery { 97866c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 97966c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 98066c7723aSAndrew Jeffery } 98166c7723aSAndrew Jeffery 98266c7723aSAndrew Jeffery template <typename T> 98366c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 98466c7723aSAndrew Jeffery void *buf) 98566c7723aSAndrew Jeffery { 98666c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 98766c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 98866c7723aSAndrew Jeffery } 98966c7723aSAndrew Jeffery 99066c7723aSAndrew Jeffery template <typename T> 99166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 99266c7723aSAndrew Jeffery void *buf) 99366c7723aSAndrew Jeffery { 99466c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 99566c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 99666c7723aSAndrew Jeffery } 99766c7723aSAndrew Jeffery 99866c7723aSAndrew Jeffery template <typename T> 99966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 100066c7723aSAndrew Jeffery void *buf) 100166c7723aSAndrew Jeffery { 100266c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 100366c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 100466c7723aSAndrew Jeffery } 100566c7723aSAndrew Jeffery #endif 100666c7723aSAndrew Jeffery 1007c63f63a2SAndrew Jeffery #endif /* BUF_H */ 1008