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 55c63f63a2SAndrew Jeffery struct pldm_msgbuf { 56062c8762SThu Nguyen uint8_t *cursor; 57c63f63a2SAndrew Jeffery ssize_t remaining; 58c63f63a2SAndrew Jeffery }; 59c63f63a2SAndrew Jeffery 60c63f63a2SAndrew Jeffery /** 61c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 62c63f63a2SAndrew Jeffery * 63c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 64c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 65c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 66c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 67c63f63a2SAndrew Jeffery * 68c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 69c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 70c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 71c63f63a2SAndrew Jeffery */ 72*07febdbbSAndrew Jeffery static inline int pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, 73*07febdbbSAndrew Jeffery const void *buf, size_t len) 74c63f63a2SAndrew Jeffery { 75c63f63a2SAndrew Jeffery if (!ctx || !buf) { 76c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 77c63f63a2SAndrew Jeffery } 78c63f63a2SAndrew Jeffery 79c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 80c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 81c63f63a2SAndrew Jeffery } 82c63f63a2SAndrew Jeffery 83*07febdbbSAndrew Jeffery if ((uintptr_t)buf + len < len) { 84c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 85c63f63a2SAndrew Jeffery } 86c63f63a2SAndrew Jeffery 87c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 88c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 89c63f63a2SAndrew Jeffery 90c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 91c63f63a2SAndrew Jeffery } 92c63f63a2SAndrew Jeffery 93c63f63a2SAndrew Jeffery /** 94c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 95c63f63a2SAndrew Jeffery * 96c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 97c63f63a2SAndrew Jeffery * 98c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 99c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 100c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 101c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 102c63f63a2SAndrew Jeffery * pointer. 103c63f63a2SAndrew Jeffery */ 104c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 105c63f63a2SAndrew Jeffery { 106c63f63a2SAndrew Jeffery if (!ctx) { 107c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 108c63f63a2SAndrew Jeffery } 109c63f63a2SAndrew Jeffery 110c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 111c63f63a2SAndrew Jeffery } 112c63f63a2SAndrew Jeffery 113c63f63a2SAndrew Jeffery /** 114db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 115db7b8324SAndrew Jeffery * 116db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 117db7b8324SAndrew Jeffery * 118db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 119db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 120db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 121db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 122db7b8324SAndrew Jeffery * pointer. 123db7b8324SAndrew Jeffery */ 124db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 125db7b8324SAndrew Jeffery { 126db7b8324SAndrew Jeffery if (!ctx) { 127db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 128db7b8324SAndrew Jeffery } 129db7b8324SAndrew Jeffery 130db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 131db7b8324SAndrew Jeffery } 132db7b8324SAndrew Jeffery 133db7b8324SAndrew Jeffery /** 134c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 135c63f63a2SAndrew Jeffery * 136c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 137c63f63a2SAndrew Jeffery * 138c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 139c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 140c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 141c63f63a2SAndrew Jeffery * bounds of the buffer. 142c63f63a2SAndrew Jeffery */ 143c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 144c63f63a2SAndrew Jeffery { 145c63f63a2SAndrew Jeffery int valid; 146c63f63a2SAndrew Jeffery 147c63f63a2SAndrew Jeffery if (!ctx) { 148c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 149c63f63a2SAndrew Jeffery } 150c63f63a2SAndrew Jeffery 151c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 152c63f63a2SAndrew Jeffery 153c63f63a2SAndrew Jeffery ctx->cursor = NULL; 154c63f63a2SAndrew Jeffery ctx->remaining = 0; 155c63f63a2SAndrew Jeffery 156c63f63a2SAndrew Jeffery return valid; 157c63f63a2SAndrew Jeffery } 158c63f63a2SAndrew Jeffery 159c63f63a2SAndrew Jeffery /** 160db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 161db7b8324SAndrew Jeffery * has been completely consumed without overflow 162db7b8324SAndrew Jeffery * 163db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 164db7b8324SAndrew Jeffery * 165db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 166db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 167db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 168db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 169db7b8324SAndrew Jeffery */ 170db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 171db7b8324SAndrew Jeffery { 172db7b8324SAndrew Jeffery int consumed; 173db7b8324SAndrew Jeffery 174db7b8324SAndrew Jeffery if (!ctx) { 175db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 176db7b8324SAndrew Jeffery } 177db7b8324SAndrew Jeffery 178db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 179db7b8324SAndrew Jeffery 180db7b8324SAndrew Jeffery ctx->cursor = NULL; 181db7b8324SAndrew Jeffery ctx->remaining = 0; 182db7b8324SAndrew Jeffery 183db7b8324SAndrew Jeffery return consumed; 184db7b8324SAndrew Jeffery } 185db7b8324SAndrew Jeffery 18666c7723aSAndrew Jeffery /* 18766c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 18866c7723aSAndrew Jeffery * 18966c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 19066c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 19166c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 19266c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 19366c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 19466c7723aSAndrew Jeffery * 19566c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 19666c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 19766c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 19866c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 19966c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 20066c7723aSAndrew Jeffery * 20166c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 20266c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 20366c7723aSAndrew Jeffery * constraints that cause some headaches: 20466c7723aSAndrew Jeffery * 20566c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 20666c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 20766c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 20866c7723aSAndrew Jeffery * 20966c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 21066c7723aSAndrew Jeffery * advantage of gtest. 21166c7723aSAndrew Jeffery * 21266c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 21366c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 21466c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 21566c7723aSAndrew Jeffery * 21666c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 21766c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 21866c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 21966c7723aSAndrew Jeffery * 22066c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 22166c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 22266c7723aSAndrew Jeffery * in C++. 22366c7723aSAndrew Jeffery * 22466c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 22566c7723aSAndrew Jeffery * 22666c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 22766c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 22866c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 22966c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 23066c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 23166c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 23266c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 23366c7723aSAndrew Jeffery * 23466c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 23566c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 23666c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 23766c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 23866c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 23966c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 24066c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 24166c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 24266c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 24366c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 24466c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 24566c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 24666c7723aSAndrew Jeffery * template argument per function. 24766c7723aSAndrew Jeffery * 24866c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 24966c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 25066c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 25166c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 25266c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 25366c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 25466c7723aSAndrew Jeffery * 25566c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 25666c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 25766c7723aSAndrew Jeffery * reasons: 25866c7723aSAndrew Jeffery * 25966c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 26066c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 26166c7723aSAndrew Jeffery * 26266c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 26366c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 26466c7723aSAndrew Jeffery */ 26566c7723aSAndrew Jeffery #ifdef __cplusplus 26666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 26766c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 26866c7723aSAndrew Jeffery #else 26966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 27066c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 27166c7723aSAndrew Jeffery #endif 27266c7723aSAndrew Jeffery 273db7b8324SAndrew Jeffery /** 274c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 275c63f63a2SAndrew Jeffery * 276c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 277c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 278c63f63a2SAndrew Jeffery * 279c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 280c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 281c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 282c63f63a2SAndrew Jeffery */ 28366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 28466c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 28566c7723aSAndrew Jeffery dst, ctx, dst) 28666c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 28766c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 288c63f63a2SAndrew Jeffery { 289c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 290c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 291c63f63a2SAndrew Jeffery } 292c63f63a2SAndrew Jeffery 29366c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 294c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 295c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 296c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 297c63f63a2SAndrew Jeffery } 298c63f63a2SAndrew Jeffery 29966c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 30066c7723aSAndrew Jeffery 301c63f63a2SAndrew Jeffery ctx->cursor++; 302c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 303c63f63a2SAndrew Jeffery } 304c63f63a2SAndrew Jeffery 30566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 30666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 30766c7723aSAndrew Jeffery ctx, dst) 30866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 30966c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 310c63f63a2SAndrew Jeffery { 311c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 312c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 313c63f63a2SAndrew Jeffery } 314c63f63a2SAndrew Jeffery 31566c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 316c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 317c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 318c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 319c63f63a2SAndrew Jeffery } 320c63f63a2SAndrew Jeffery 32166c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 322c63f63a2SAndrew Jeffery ctx->cursor++; 323c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 324c63f63a2SAndrew Jeffery } 325c63f63a2SAndrew Jeffery 32666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 32766c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 32866c7723aSAndrew Jeffery dst, ctx, dst) 32966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 33066c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 33166c7723aSAndrew Jeffery void *dst) 332c63f63a2SAndrew Jeffery { 333c63f63a2SAndrew Jeffery uint16_t ldst; 334c63f63a2SAndrew Jeffery 335c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 336c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 337c63f63a2SAndrew Jeffery } 338c63f63a2SAndrew Jeffery 339c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 340c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 341c63f63a2SAndrew Jeffery // we've overflowed. 342c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 343c63f63a2SAndrew Jeffery 344c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 345c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 346c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 347c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 348c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 349c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 350c63f63a2SAndrew Jeffery } 351c63f63a2SAndrew Jeffery 352c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 353c63f63a2SAndrew Jeffery // issues on the target architecture 354c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 355c63f63a2SAndrew Jeffery 356c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 35766c7723aSAndrew Jeffery ldst = le16toh(ldst); 35866c7723aSAndrew Jeffery 35966c7723aSAndrew Jeffery // Allow storing to unaligned 36066c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 36166c7723aSAndrew Jeffery 362c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 363c63f63a2SAndrew Jeffery 364c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 365c63f63a2SAndrew Jeffery } 366c63f63a2SAndrew Jeffery 36766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 36866c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 36966c7723aSAndrew Jeffery dst, ctx, dst) 37066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 37166c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 372c63f63a2SAndrew Jeffery { 373c63f63a2SAndrew Jeffery int16_t ldst; 374c63f63a2SAndrew Jeffery 375c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 376c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 377c63f63a2SAndrew Jeffery } 378c63f63a2SAndrew Jeffery 379c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 380c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 381c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 382c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 383c63f63a2SAndrew Jeffery } 384c63f63a2SAndrew Jeffery 385c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 386c63f63a2SAndrew Jeffery 38766c7723aSAndrew Jeffery ldst = le16toh(ldst); 38866c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 389c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 390c63f63a2SAndrew Jeffery 391c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 392c63f63a2SAndrew Jeffery } 393c63f63a2SAndrew Jeffery 39466c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 39566c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 39666c7723aSAndrew Jeffery dst, ctx, dst) 39766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 39866c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 39966c7723aSAndrew Jeffery void *dst) 400c63f63a2SAndrew Jeffery { 401c63f63a2SAndrew Jeffery uint32_t ldst; 402c63f63a2SAndrew Jeffery 403c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 404c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 405c63f63a2SAndrew Jeffery } 406c63f63a2SAndrew Jeffery 407c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 408c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 409c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 410c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 411c63f63a2SAndrew Jeffery } 412c63f63a2SAndrew Jeffery 413c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 414c63f63a2SAndrew Jeffery 41566c7723aSAndrew Jeffery ldst = le32toh(ldst); 41666c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 417c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 418c63f63a2SAndrew Jeffery 419c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 420c63f63a2SAndrew Jeffery } 421c63f63a2SAndrew Jeffery 42266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 42366c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 42466c7723aSAndrew Jeffery dst, ctx, dst) 42566c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 42666c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 427c63f63a2SAndrew Jeffery { 428c63f63a2SAndrew Jeffery int32_t ldst; 429c63f63a2SAndrew Jeffery 430c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 431c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 432c63f63a2SAndrew Jeffery } 433c63f63a2SAndrew 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 = le32toh(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_real32(ctx, dst) \ 45066c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 45166c7723aSAndrew Jeffery dst, ctx, dst) 45266c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 45366c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, 45466c7723aSAndrew Jeffery void *dst) 455c63f63a2SAndrew Jeffery { 456c63f63a2SAndrew Jeffery uint32_t ldst; 457c63f63a2SAndrew Jeffery 45866c7723aSAndrew Jeffery _Static_assert(sizeof(real32_t) == sizeof(ldst), 45966c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 46066c7723aSAndrew Jeffery 461c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 462c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 463c63f63a2SAndrew Jeffery } 464c63f63a2SAndrew Jeffery 465c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 466c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 467c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 468c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 469c63f63a2SAndrew Jeffery } 470c63f63a2SAndrew Jeffery 471c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 472c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 47366c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 47466c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 475c63f63a2SAndrew Jeffery 476c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 477c63f63a2SAndrew Jeffery } 478c63f63a2SAndrew Jeffery 47966c7723aSAndrew Jeffery /** 48066c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 48166c7723aSAndrew Jeffery * 48266c7723aSAndrew Jeffery * @param ctx The msgbuf context object 48366c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 48466c7723aSAndrew Jeffery * extracted 48566c7723aSAndrew Jeffery * 48666c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 48766c7723aSAndrew Jeffery */ 488c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 48966c7723aSAndrew Jeffery _Generic((dst), \ 49066c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 49166c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 49266c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 49366c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 49466c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 49566c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 49666c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 49766c7723aSAndrew Jeffery 49866c7723aSAndrew Jeffery /** 49966c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 50066c7723aSAndrew Jeffery * 50166c7723aSAndrew Jeffery * @param ctx The msgbuf context object 50266c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 50366c7723aSAndrew Jeffery * cursor should be extracted 50466c7723aSAndrew Jeffery * 50566c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 50666c7723aSAndrew Jeffery */ 50766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 50866c7723aSAndrew Jeffery _Generic((dst), \ 50966c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 51066c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 51166c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 51266c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 51366c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 51466c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 51566c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 516c63f63a2SAndrew Jeffery 517369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 518369b121aSAndrew Jeffery uint8_t *dst, size_t count) 519369b121aSAndrew Jeffery { 520369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 521369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 522369b121aSAndrew Jeffery } 523369b121aSAndrew Jeffery 524369b121aSAndrew Jeffery if (!count) { 525369b121aSAndrew Jeffery return PLDM_SUCCESS; 526369b121aSAndrew Jeffery } 527369b121aSAndrew Jeffery 528a065eccbSAndrew Jeffery if (count >= SSIZE_MAX) { 529369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 530369b121aSAndrew Jeffery } 531369b121aSAndrew Jeffery 532a065eccbSAndrew Jeffery ctx->remaining -= (ssize_t)count; 533369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 534369b121aSAndrew Jeffery if (ctx->remaining < 0) { 535369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 536369b121aSAndrew Jeffery } 537369b121aSAndrew Jeffery 538a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 539a065eccbSAndrew Jeffery ctx->cursor += count; 540369b121aSAndrew Jeffery 541369b121aSAndrew Jeffery return PLDM_SUCCESS; 542369b121aSAndrew Jeffery } 543369b121aSAndrew Jeffery 544369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 54537dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 54637dd6a3dSAndrew Jeffery count) 547369b121aSAndrew Jeffery 548062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, 549062c8762SThu Nguyen const uint32_t src) 550062c8762SThu Nguyen { 551062c8762SThu Nguyen uint32_t val = htole32(src); 552062c8762SThu Nguyen 553062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 554062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 555062c8762SThu Nguyen } 556062c8762SThu Nguyen 557062c8762SThu Nguyen ctx->remaining -= sizeof(src); 558062c8762SThu Nguyen assert(ctx->remaining >= 0); 559062c8762SThu Nguyen if (ctx->remaining < 0) { 560062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 561062c8762SThu Nguyen } 562062c8762SThu Nguyen 563062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 564062c8762SThu Nguyen ctx->cursor += sizeof(src); 565062c8762SThu Nguyen 566062c8762SThu Nguyen return PLDM_SUCCESS; 567062c8762SThu Nguyen } 568062c8762SThu Nguyen 569062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, 570062c8762SThu Nguyen const uint16_t src) 571062c8762SThu Nguyen { 572062c8762SThu Nguyen uint16_t val = htole16(src); 573062c8762SThu Nguyen 574062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 575062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 576062c8762SThu Nguyen } 577062c8762SThu Nguyen 578062c8762SThu Nguyen ctx->remaining -= sizeof(src); 579062c8762SThu Nguyen assert(ctx->remaining >= 0); 580062c8762SThu Nguyen if (ctx->remaining < 0) { 581062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 582062c8762SThu Nguyen } 583062c8762SThu Nguyen 584062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 585062c8762SThu Nguyen ctx->cursor += sizeof(src); 586062c8762SThu Nguyen 587062c8762SThu Nguyen return PLDM_SUCCESS; 588062c8762SThu Nguyen } 589062c8762SThu Nguyen 590062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, 591062c8762SThu Nguyen const uint8_t src) 592062c8762SThu Nguyen { 593062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 594062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 595062c8762SThu Nguyen } 596062c8762SThu Nguyen 597062c8762SThu Nguyen ctx->remaining -= sizeof(src); 598062c8762SThu Nguyen assert(ctx->remaining >= 0); 599062c8762SThu Nguyen if (ctx->remaining < 0) { 600062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 601062c8762SThu Nguyen } 602062c8762SThu Nguyen 603062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 604062c8762SThu Nguyen ctx->cursor += sizeof(src); 605062c8762SThu Nguyen 606062c8762SThu Nguyen return PLDM_SUCCESS; 607062c8762SThu Nguyen } 608062c8762SThu Nguyen 609062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, 610062c8762SThu Nguyen const int32_t src) 611062c8762SThu Nguyen { 612062c8762SThu Nguyen int32_t val = htole32(src); 613062c8762SThu Nguyen 614062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 615062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 616062c8762SThu Nguyen } 617062c8762SThu Nguyen 618062c8762SThu Nguyen ctx->remaining -= sizeof(src); 619062c8762SThu Nguyen assert(ctx->remaining >= 0); 620062c8762SThu Nguyen if (ctx->remaining < 0) { 621062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 622062c8762SThu Nguyen } 623062c8762SThu Nguyen 624062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 625062c8762SThu Nguyen ctx->cursor += sizeof(src); 626062c8762SThu Nguyen 627062c8762SThu Nguyen return PLDM_SUCCESS; 628062c8762SThu Nguyen } 629062c8762SThu Nguyen 630062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, 631062c8762SThu Nguyen const int16_t src) 632062c8762SThu Nguyen { 633062c8762SThu Nguyen int16_t val = htole16(src); 634062c8762SThu Nguyen 635062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 636062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 637062c8762SThu Nguyen } 638062c8762SThu Nguyen 639062c8762SThu Nguyen ctx->remaining -= sizeof(src); 640062c8762SThu Nguyen assert(ctx->remaining >= 0); 641062c8762SThu Nguyen if (ctx->remaining < 0) { 642062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 643062c8762SThu Nguyen } 644062c8762SThu Nguyen 645062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 646062c8762SThu Nguyen ctx->cursor += sizeof(src); 647062c8762SThu Nguyen 648062c8762SThu Nguyen return PLDM_SUCCESS; 649062c8762SThu Nguyen } 650062c8762SThu Nguyen 651062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, 652062c8762SThu Nguyen const int8_t src) 653062c8762SThu Nguyen { 654062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 655062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 656062c8762SThu Nguyen } 657062c8762SThu Nguyen 658062c8762SThu Nguyen ctx->remaining -= sizeof(src); 659062c8762SThu Nguyen assert(ctx->remaining >= 0); 660062c8762SThu Nguyen if (ctx->remaining < 0) { 661062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 662062c8762SThu Nguyen } 663062c8762SThu Nguyen 664062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 665062c8762SThu Nguyen ctx->cursor += sizeof(src); 666062c8762SThu Nguyen 667062c8762SThu Nguyen return PLDM_SUCCESS; 668062c8762SThu Nguyen } 669062c8762SThu Nguyen 670062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 67137dd6a3dSAndrew Jeffery _Generic((src), \ 67237dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 67337dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 67437dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 67537dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 67637dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 67737dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 678062c8762SThu Nguyen 679062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, 680062c8762SThu Nguyen const uint8_t *src, 681062c8762SThu Nguyen size_t count) 682062c8762SThu Nguyen { 683062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 684062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 685062c8762SThu Nguyen } 686062c8762SThu Nguyen 687062c8762SThu Nguyen if (!count) { 688062c8762SThu Nguyen return PLDM_SUCCESS; 689062c8762SThu Nguyen } 690062c8762SThu Nguyen 691a065eccbSAndrew Jeffery if (count >= SSIZE_MAX) { 692062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 693062c8762SThu Nguyen } 694062c8762SThu Nguyen 695a065eccbSAndrew Jeffery ctx->remaining -= (ssize_t)count; 696062c8762SThu Nguyen assert(ctx->remaining >= 0); 697062c8762SThu Nguyen if (ctx->remaining < 0) { 698062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 699062c8762SThu Nguyen } 700062c8762SThu Nguyen 701a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 702a065eccbSAndrew Jeffery ctx->cursor += count; 703062c8762SThu Nguyen 704062c8762SThu Nguyen return PLDM_SUCCESS; 705062c8762SThu Nguyen } 706062c8762SThu Nguyen 707062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 70837dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 70937dd6a3dSAndrew Jeffery count) 710062c8762SThu Nguyen 711062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, 712062c8762SThu Nguyen size_t required, void **cursor) 713062c8762SThu Nguyen { 714062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 715062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 716062c8762SThu Nguyen } 717062c8762SThu Nguyen 718062c8762SThu Nguyen if (required > SSIZE_MAX) { 719062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 720062c8762SThu Nguyen } 721062c8762SThu Nguyen 722062c8762SThu Nguyen ctx->remaining -= (ssize_t)required; 723062c8762SThu Nguyen assert(ctx->remaining >= 0); 724062c8762SThu Nguyen if (ctx->remaining < 0) { 725062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 726062c8762SThu Nguyen } 727062c8762SThu Nguyen 728062c8762SThu Nguyen *cursor = ctx->cursor; 729062c8762SThu Nguyen ctx->cursor += required; 730062c8762SThu Nguyen 731062c8762SThu Nguyen return PLDM_SUCCESS; 732062c8762SThu Nguyen } 733062c8762SThu Nguyen 734062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, 735062c8762SThu Nguyen void **cursor, size_t *len) 736062c8762SThu Nguyen { 737062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 738062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 739062c8762SThu Nguyen } 740062c8762SThu Nguyen 741062c8762SThu Nguyen assert(ctx->remaining >= 0); 742062c8762SThu Nguyen if (ctx->remaining < 0) { 743062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 744062c8762SThu Nguyen } 745062c8762SThu Nguyen 746062c8762SThu Nguyen *cursor = ctx->cursor; 747062c8762SThu Nguyen ctx->cursor += ctx->remaining; 748062c8762SThu Nguyen *len = ctx->remaining; 749062c8762SThu Nguyen ctx->remaining = 0; 750062c8762SThu Nguyen 751062c8762SThu Nguyen return PLDM_SUCCESS; 752062c8762SThu Nguyen } 753c63f63a2SAndrew Jeffery #ifdef __cplusplus 754c63f63a2SAndrew Jeffery } 755c63f63a2SAndrew Jeffery #endif 756c63f63a2SAndrew Jeffery 75766c7723aSAndrew Jeffery #ifdef __cplusplus 75866c7723aSAndrew Jeffery #include <type_traits> 75966c7723aSAndrew Jeffery 76066c7723aSAndrew Jeffery template <typename T> 76166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 76266c7723aSAndrew Jeffery void *buf) 76366c7723aSAndrew Jeffery { 76466c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 76566c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 76666c7723aSAndrew Jeffery } 76766c7723aSAndrew Jeffery 76866c7723aSAndrew Jeffery template <typename T> 76966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 77066c7723aSAndrew Jeffery void *buf) 77166c7723aSAndrew Jeffery { 77266c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 77366c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 77466c7723aSAndrew Jeffery } 77566c7723aSAndrew Jeffery 77666c7723aSAndrew Jeffery template <typename T> 77766c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 77866c7723aSAndrew Jeffery void *buf) 77966c7723aSAndrew Jeffery { 78066c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 78166c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 78266c7723aSAndrew Jeffery } 78366c7723aSAndrew Jeffery 78466c7723aSAndrew Jeffery template <typename T> 78566c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 78666c7723aSAndrew Jeffery void *buf) 78766c7723aSAndrew Jeffery { 78866c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 78966c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 79066c7723aSAndrew Jeffery } 79166c7723aSAndrew Jeffery 79266c7723aSAndrew Jeffery template <typename T> 79366c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 79466c7723aSAndrew Jeffery void *buf) 79566c7723aSAndrew Jeffery { 79666c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 79766c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 79866c7723aSAndrew Jeffery } 79966c7723aSAndrew Jeffery 80066c7723aSAndrew Jeffery template <typename T> 80166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 80266c7723aSAndrew Jeffery void *buf) 80366c7723aSAndrew Jeffery { 80466c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 80566c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 80666c7723aSAndrew Jeffery } 80766c7723aSAndrew Jeffery 80866c7723aSAndrew Jeffery template <typename T> 80966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 81066c7723aSAndrew Jeffery void *buf) 81166c7723aSAndrew Jeffery { 81266c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 81366c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 81466c7723aSAndrew Jeffery } 81566c7723aSAndrew Jeffery #endif 81666c7723aSAndrew Jeffery 817c63f63a2SAndrew Jeffery #endif /* BUF_H */ 818