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 5*66c7723aSAndrew Jeffery /* 6*66c7723aSAndrew Jeffery * Historically, many of the structs exposed in libpldm's public headers are 7*66c7723aSAndrew Jeffery * defined with __attribute__((packed)). This is unfortunate: it gives the 8*66c7723aSAndrew Jeffery * impression that a wire-format buffer can be cast to the message type to make 9*66c7723aSAndrew Jeffery * the message's fields easily accessible. As it turns out, that's not 10*66c7723aSAndrew Jeffery * that's valid for several reasons: 11*66c7723aSAndrew Jeffery * 12*66c7723aSAndrew Jeffery * 1. Casting the wire-format buffer to a struct of the message type doesn't 13*66c7723aSAndrew Jeffery * abstract the endianness of message field values 14*66c7723aSAndrew Jeffery * 15*66c7723aSAndrew Jeffery * 2. Some messages contain packed tagged union fields which cannot be properly 16*66c7723aSAndrew Jeffery * described in a C struct. 17*66c7723aSAndrew Jeffery * 18*66c7723aSAndrew Jeffery * The msgbuf APIs exist to assist with (un)packing the wire-format in a way 19*66c7723aSAndrew Jeffery * that is type-safe, spatially memory-safe, endian-safe, performant, and 20*66c7723aSAndrew Jeffery * free of undefined-behaviour. Message structs that are added to the public 21*66c7723aSAndrew Jeffery * library API should no-longer be marked __attribute__((packed)), and the 22*66c7723aSAndrew Jeffery * implementation of their encode and decode functions must exploit the msgbuf 23*66c7723aSAndrew Jeffery * API. 24*66c7723aSAndrew Jeffery * 25*66c7723aSAndrew Jeffery * However, we would like to allow implementation of codec functions in terms of 26*66c7723aSAndrew Jeffery * msgbuf APIs even if they're decoding a message into a (historically) packed 27*66c7723aSAndrew Jeffery * struct. Some of the complexity that follows is a consequence of the packed/ 28*66c7723aSAndrew Jeffery * unpacked conflict. 29*66c7723aSAndrew Jeffery */ 30*66c7723aSAndrew 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 45*66c7723aSAndrew Jeffery #include "compiler.h" 46*66c7723aSAndrew Jeffery 47c63f63a2SAndrew Jeffery #include <assert.h> 48c63f63a2SAndrew Jeffery #include <endian.h> 49c63f63a2SAndrew Jeffery #include <limits.h> 50c63f63a2SAndrew Jeffery #include <stdbool.h> 51*66c7723aSAndrew 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 */ 725646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int 735646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 745646f23bSAndrew Jeffery size_t len) 75c63f63a2SAndrew Jeffery { 76c63f63a2SAndrew Jeffery uint8_t *end; 77c63f63a2SAndrew Jeffery 78c63f63a2SAndrew Jeffery if (!ctx || !buf) { 79c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 80c63f63a2SAndrew Jeffery } 81c63f63a2SAndrew Jeffery 82c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 83c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 84c63f63a2SAndrew Jeffery } 85c63f63a2SAndrew Jeffery 86c63f63a2SAndrew Jeffery end = (uint8_t *)buf + len; 87c63f63a2SAndrew Jeffery if (end && end < (uint8_t *)buf) { 88c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 89c63f63a2SAndrew Jeffery } 90c63f63a2SAndrew Jeffery 91c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 92c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 93c63f63a2SAndrew Jeffery 94c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 95c63f63a2SAndrew Jeffery } 96c63f63a2SAndrew Jeffery 97c63f63a2SAndrew Jeffery /** 98c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 99c63f63a2SAndrew Jeffery * 100c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 101c63f63a2SAndrew Jeffery * 102c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 103c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 104c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 105c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 106c63f63a2SAndrew Jeffery * pointer. 107c63f63a2SAndrew Jeffery */ 108c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 109c63f63a2SAndrew Jeffery { 110c63f63a2SAndrew Jeffery if (!ctx) { 111c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 112c63f63a2SAndrew Jeffery } 113c63f63a2SAndrew Jeffery 114c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 115c63f63a2SAndrew Jeffery } 116c63f63a2SAndrew Jeffery 117c63f63a2SAndrew Jeffery /** 118db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 119db7b8324SAndrew Jeffery * 120db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 121db7b8324SAndrew Jeffery * 122db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 123db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 124db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 125db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 126db7b8324SAndrew Jeffery * pointer. 127db7b8324SAndrew Jeffery */ 128db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 129db7b8324SAndrew Jeffery { 130db7b8324SAndrew Jeffery if (!ctx) { 131db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 132db7b8324SAndrew Jeffery } 133db7b8324SAndrew Jeffery 134db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 135db7b8324SAndrew Jeffery } 136db7b8324SAndrew Jeffery 137db7b8324SAndrew Jeffery /** 138c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 139c63f63a2SAndrew Jeffery * 140c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 141c63f63a2SAndrew Jeffery * 142c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 143c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 144c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 145c63f63a2SAndrew Jeffery * bounds of the buffer. 146c63f63a2SAndrew Jeffery */ 147c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 148c63f63a2SAndrew Jeffery { 149c63f63a2SAndrew Jeffery int valid; 150c63f63a2SAndrew Jeffery 151c63f63a2SAndrew Jeffery if (!ctx) { 152c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 153c63f63a2SAndrew Jeffery } 154c63f63a2SAndrew Jeffery 155c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 156c63f63a2SAndrew Jeffery 157c63f63a2SAndrew Jeffery ctx->cursor = NULL; 158c63f63a2SAndrew Jeffery ctx->remaining = 0; 159c63f63a2SAndrew Jeffery 160c63f63a2SAndrew Jeffery return valid; 161c63f63a2SAndrew Jeffery } 162c63f63a2SAndrew Jeffery 163c63f63a2SAndrew Jeffery /** 164db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 165db7b8324SAndrew Jeffery * has been completely consumed without overflow 166db7b8324SAndrew Jeffery * 167db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 168db7b8324SAndrew Jeffery * 169db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 170db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 171db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 172db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 173db7b8324SAndrew Jeffery */ 174db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 175db7b8324SAndrew Jeffery { 176db7b8324SAndrew Jeffery int consumed; 177db7b8324SAndrew Jeffery 178db7b8324SAndrew Jeffery if (!ctx) { 179db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 180db7b8324SAndrew Jeffery } 181db7b8324SAndrew Jeffery 182db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 183db7b8324SAndrew Jeffery 184db7b8324SAndrew Jeffery ctx->cursor = NULL; 185db7b8324SAndrew Jeffery ctx->remaining = 0; 186db7b8324SAndrew Jeffery 187db7b8324SAndrew Jeffery return consumed; 188db7b8324SAndrew Jeffery } 189db7b8324SAndrew Jeffery 190*66c7723aSAndrew Jeffery /* 191*66c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 192*66c7723aSAndrew Jeffery * 193*66c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 194*66c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 195*66c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 196*66c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 197*66c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 198*66c7723aSAndrew Jeffery * 199*66c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 200*66c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 201*66c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 202*66c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 203*66c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 204*66c7723aSAndrew Jeffery * 205*66c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 206*66c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 207*66c7723aSAndrew Jeffery * constraints that cause some headaches: 208*66c7723aSAndrew Jeffery * 209*66c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 210*66c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 211*66c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 212*66c7723aSAndrew Jeffery * 213*66c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 214*66c7723aSAndrew Jeffery * advantage of gtest. 215*66c7723aSAndrew Jeffery * 216*66c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 217*66c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 218*66c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 219*66c7723aSAndrew Jeffery * 220*66c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 221*66c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 222*66c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 223*66c7723aSAndrew Jeffery * 224*66c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 225*66c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 226*66c7723aSAndrew Jeffery * in C++. 227*66c7723aSAndrew Jeffery * 228*66c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 229*66c7723aSAndrew Jeffery * 230*66c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 231*66c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 232*66c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 233*66c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 234*66c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 235*66c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 236*66c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 237*66c7723aSAndrew Jeffery * 238*66c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 239*66c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 240*66c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 241*66c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 242*66c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 243*66c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 244*66c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 245*66c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 246*66c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 247*66c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 248*66c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 249*66c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 250*66c7723aSAndrew Jeffery * template argument per function. 251*66c7723aSAndrew Jeffery * 252*66c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 253*66c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 254*66c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 255*66c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 256*66c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 257*66c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 258*66c7723aSAndrew Jeffery * 259*66c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 260*66c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 261*66c7723aSAndrew Jeffery * reasons: 262*66c7723aSAndrew Jeffery * 263*66c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 264*66c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 265*66c7723aSAndrew Jeffery * 266*66c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 267*66c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 268*66c7723aSAndrew Jeffery */ 269*66c7723aSAndrew Jeffery #ifdef __cplusplus 270*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 271*66c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 272*66c7723aSAndrew Jeffery #else 273*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 274*66c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 275*66c7723aSAndrew Jeffery #endif 276*66c7723aSAndrew Jeffery 277db7b8324SAndrew Jeffery /** 278c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 279c63f63a2SAndrew Jeffery * 280c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 281c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 282c63f63a2SAndrew Jeffery * 283c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 284c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 285c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 286c63f63a2SAndrew Jeffery */ 287*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 288*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 289*66c7723aSAndrew Jeffery dst, ctx, dst) 290*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 291*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 292c63f63a2SAndrew Jeffery { 293c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 294c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 295c63f63a2SAndrew Jeffery } 296c63f63a2SAndrew Jeffery 297*66c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 298c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 299c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 300c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 301c63f63a2SAndrew Jeffery } 302c63f63a2SAndrew Jeffery 303*66c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 304*66c7723aSAndrew Jeffery 305c63f63a2SAndrew Jeffery ctx->cursor++; 306c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 307c63f63a2SAndrew Jeffery } 308c63f63a2SAndrew Jeffery 309*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 310*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 311*66c7723aSAndrew Jeffery ctx, dst) 312*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 313*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 314c63f63a2SAndrew Jeffery { 315c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 316c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 317c63f63a2SAndrew Jeffery } 318c63f63a2SAndrew Jeffery 319*66c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 320c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 321c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 322c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 323c63f63a2SAndrew Jeffery } 324c63f63a2SAndrew Jeffery 325*66c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 326c63f63a2SAndrew Jeffery ctx->cursor++; 327c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 328c63f63a2SAndrew Jeffery } 329c63f63a2SAndrew Jeffery 330*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 331*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 332*66c7723aSAndrew Jeffery dst, ctx, dst) 333*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 334*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 335*66c7723aSAndrew Jeffery void *dst) 336c63f63a2SAndrew Jeffery { 337c63f63a2SAndrew Jeffery uint16_t ldst; 338c63f63a2SAndrew Jeffery 339c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 340c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 341c63f63a2SAndrew Jeffery } 342c63f63a2SAndrew Jeffery 343c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 344c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 345c63f63a2SAndrew Jeffery // we've overflowed. 346c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 347c63f63a2SAndrew Jeffery 348c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 349c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 350c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 351c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 352c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 353c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 354c63f63a2SAndrew Jeffery } 355c63f63a2SAndrew Jeffery 356c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 357c63f63a2SAndrew Jeffery // issues on the target architecture 358c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 359c63f63a2SAndrew Jeffery 360c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 361*66c7723aSAndrew Jeffery ldst = le16toh(ldst); 362*66c7723aSAndrew Jeffery 363*66c7723aSAndrew Jeffery // Allow storing to unaligned 364*66c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 365*66c7723aSAndrew Jeffery 366c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 367c63f63a2SAndrew Jeffery 368c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 369c63f63a2SAndrew Jeffery } 370c63f63a2SAndrew Jeffery 371*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 372*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 373*66c7723aSAndrew Jeffery dst, ctx, dst) 374*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 375*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 376c63f63a2SAndrew Jeffery { 377c63f63a2SAndrew Jeffery int16_t ldst; 378c63f63a2SAndrew Jeffery 379c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 380c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 381c63f63a2SAndrew Jeffery } 382c63f63a2SAndrew Jeffery 383c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 384c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 385c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 386c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 387c63f63a2SAndrew Jeffery } 388c63f63a2SAndrew Jeffery 389c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 390c63f63a2SAndrew Jeffery 391*66c7723aSAndrew Jeffery ldst = le16toh(ldst); 392*66c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 393c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 394c63f63a2SAndrew Jeffery 395c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 396c63f63a2SAndrew Jeffery } 397c63f63a2SAndrew Jeffery 398*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 399*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 400*66c7723aSAndrew Jeffery dst, ctx, dst) 401*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 402*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 403*66c7723aSAndrew Jeffery void *dst) 404c63f63a2SAndrew Jeffery { 405c63f63a2SAndrew Jeffery uint32_t ldst; 406c63f63a2SAndrew Jeffery 407c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 408c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 409c63f63a2SAndrew Jeffery } 410c63f63a2SAndrew Jeffery 411c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 412c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 413c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 414c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 415c63f63a2SAndrew Jeffery } 416c63f63a2SAndrew Jeffery 417c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 418c63f63a2SAndrew Jeffery 419*66c7723aSAndrew Jeffery ldst = le32toh(ldst); 420*66c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 421c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 422c63f63a2SAndrew Jeffery 423c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 424c63f63a2SAndrew Jeffery } 425c63f63a2SAndrew Jeffery 426*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 427*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 428*66c7723aSAndrew Jeffery dst, ctx, dst) 429*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 430*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 431c63f63a2SAndrew Jeffery { 432c63f63a2SAndrew Jeffery int32_t ldst; 433c63f63a2SAndrew Jeffery 434c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 435c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 436c63f63a2SAndrew Jeffery } 437c63f63a2SAndrew Jeffery 438c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 439c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 440c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 441c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 442c63f63a2SAndrew Jeffery } 443c63f63a2SAndrew Jeffery 444c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 445c63f63a2SAndrew Jeffery 446*66c7723aSAndrew Jeffery ldst = le32toh(ldst); 447*66c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 448c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 449c63f63a2SAndrew Jeffery 450c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 451c63f63a2SAndrew Jeffery } 452c63f63a2SAndrew Jeffery 453*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst) \ 454*66c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 455*66c7723aSAndrew Jeffery dst, ctx, dst) 456*66c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 457*66c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, 458*66c7723aSAndrew Jeffery void *dst) 459c63f63a2SAndrew Jeffery { 460c63f63a2SAndrew Jeffery uint32_t ldst; 461c63f63a2SAndrew Jeffery 462*66c7723aSAndrew Jeffery _Static_assert(sizeof(real32_t) == sizeof(ldst), 463*66c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 464*66c7723aSAndrew Jeffery 465c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 466c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 467c63f63a2SAndrew Jeffery } 468c63f63a2SAndrew Jeffery 469c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 470c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 471c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 472c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 473c63f63a2SAndrew Jeffery } 474c63f63a2SAndrew Jeffery 475c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 476c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 477*66c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 478*66c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 479c63f63a2SAndrew Jeffery 480c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 481c63f63a2SAndrew Jeffery } 482c63f63a2SAndrew Jeffery 483*66c7723aSAndrew Jeffery /** 484*66c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 485*66c7723aSAndrew Jeffery * 486*66c7723aSAndrew Jeffery * @param ctx The msgbuf context object 487*66c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 488*66c7723aSAndrew Jeffery * extracted 489*66c7723aSAndrew Jeffery * 490*66c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 491*66c7723aSAndrew Jeffery */ 492c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 493*66c7723aSAndrew Jeffery _Generic((dst), \ 494*66c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 495*66c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 496*66c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 497*66c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 498*66c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 499*66c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 500*66c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 501*66c7723aSAndrew Jeffery 502*66c7723aSAndrew Jeffery /** 503*66c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 504*66c7723aSAndrew Jeffery * 505*66c7723aSAndrew Jeffery * @param ctx The msgbuf context object 506*66c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 507*66c7723aSAndrew Jeffery * cursor should be extracted 508*66c7723aSAndrew Jeffery * 509*66c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 510*66c7723aSAndrew Jeffery */ 511*66c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 512*66c7723aSAndrew Jeffery _Generic((dst), \ 513*66c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 514*66c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 515*66c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 516*66c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 517*66c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 518*66c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 519*66c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 520c63f63a2SAndrew Jeffery 521369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 522369b121aSAndrew Jeffery uint8_t *dst, size_t count) 523369b121aSAndrew Jeffery { 524369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 525369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 526369b121aSAndrew Jeffery } 527369b121aSAndrew Jeffery 528369b121aSAndrew Jeffery if (!count) { 529369b121aSAndrew Jeffery return PLDM_SUCCESS; 530369b121aSAndrew Jeffery } 531369b121aSAndrew Jeffery 532a065eccbSAndrew Jeffery if (count >= SSIZE_MAX) { 533369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 534369b121aSAndrew Jeffery } 535369b121aSAndrew Jeffery 536a065eccbSAndrew Jeffery ctx->remaining -= (ssize_t)count; 537369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 538369b121aSAndrew Jeffery if (ctx->remaining < 0) { 539369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 540369b121aSAndrew Jeffery } 541369b121aSAndrew Jeffery 542a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 543a065eccbSAndrew Jeffery ctx->cursor += count; 544369b121aSAndrew Jeffery 545369b121aSAndrew Jeffery return PLDM_SUCCESS; 546369b121aSAndrew Jeffery } 547369b121aSAndrew Jeffery 548369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 54937dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 55037dd6a3dSAndrew Jeffery count) 551369b121aSAndrew Jeffery 552062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, 553062c8762SThu Nguyen const uint32_t src) 554062c8762SThu Nguyen { 555062c8762SThu Nguyen uint32_t val = htole32(src); 556062c8762SThu Nguyen 557062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 558062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 559062c8762SThu Nguyen } 560062c8762SThu Nguyen 561062c8762SThu Nguyen ctx->remaining -= sizeof(src); 562062c8762SThu Nguyen assert(ctx->remaining >= 0); 563062c8762SThu Nguyen if (ctx->remaining < 0) { 564062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 565062c8762SThu Nguyen } 566062c8762SThu Nguyen 567062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 568062c8762SThu Nguyen ctx->cursor += sizeof(src); 569062c8762SThu Nguyen 570062c8762SThu Nguyen return PLDM_SUCCESS; 571062c8762SThu Nguyen } 572062c8762SThu Nguyen 573062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, 574062c8762SThu Nguyen const uint16_t src) 575062c8762SThu Nguyen { 576062c8762SThu Nguyen uint16_t val = htole16(src); 577062c8762SThu Nguyen 578062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 579062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 580062c8762SThu Nguyen } 581062c8762SThu Nguyen 582062c8762SThu Nguyen ctx->remaining -= sizeof(src); 583062c8762SThu Nguyen assert(ctx->remaining >= 0); 584062c8762SThu Nguyen if (ctx->remaining < 0) { 585062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 586062c8762SThu Nguyen } 587062c8762SThu Nguyen 588062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 589062c8762SThu Nguyen ctx->cursor += sizeof(src); 590062c8762SThu Nguyen 591062c8762SThu Nguyen return PLDM_SUCCESS; 592062c8762SThu Nguyen } 593062c8762SThu Nguyen 594062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, 595062c8762SThu Nguyen const uint8_t src) 596062c8762SThu Nguyen { 597062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 598062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 599062c8762SThu Nguyen } 600062c8762SThu Nguyen 601062c8762SThu Nguyen ctx->remaining -= sizeof(src); 602062c8762SThu Nguyen assert(ctx->remaining >= 0); 603062c8762SThu Nguyen if (ctx->remaining < 0) { 604062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 605062c8762SThu Nguyen } 606062c8762SThu Nguyen 607062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 608062c8762SThu Nguyen ctx->cursor += sizeof(src); 609062c8762SThu Nguyen 610062c8762SThu Nguyen return PLDM_SUCCESS; 611062c8762SThu Nguyen } 612062c8762SThu Nguyen 613062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, 614062c8762SThu Nguyen const int32_t src) 615062c8762SThu Nguyen { 616062c8762SThu Nguyen int32_t val = htole32(src); 617062c8762SThu Nguyen 618062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 619062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 620062c8762SThu Nguyen } 621062c8762SThu Nguyen 622062c8762SThu Nguyen ctx->remaining -= sizeof(src); 623062c8762SThu Nguyen assert(ctx->remaining >= 0); 624062c8762SThu Nguyen if (ctx->remaining < 0) { 625062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 626062c8762SThu Nguyen } 627062c8762SThu Nguyen 628062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 629062c8762SThu Nguyen ctx->cursor += sizeof(src); 630062c8762SThu Nguyen 631062c8762SThu Nguyen return PLDM_SUCCESS; 632062c8762SThu Nguyen } 633062c8762SThu Nguyen 634062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, 635062c8762SThu Nguyen const int16_t src) 636062c8762SThu Nguyen { 637062c8762SThu Nguyen int16_t val = htole16(src); 638062c8762SThu Nguyen 639062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 640062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 641062c8762SThu Nguyen } 642062c8762SThu Nguyen 643062c8762SThu Nguyen ctx->remaining -= sizeof(src); 644062c8762SThu Nguyen assert(ctx->remaining >= 0); 645062c8762SThu Nguyen if (ctx->remaining < 0) { 646062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 647062c8762SThu Nguyen } 648062c8762SThu Nguyen 649062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 650062c8762SThu Nguyen ctx->cursor += sizeof(src); 651062c8762SThu Nguyen 652062c8762SThu Nguyen return PLDM_SUCCESS; 653062c8762SThu Nguyen } 654062c8762SThu Nguyen 655062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, 656062c8762SThu Nguyen const int8_t src) 657062c8762SThu Nguyen { 658062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 659062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 660062c8762SThu Nguyen } 661062c8762SThu Nguyen 662062c8762SThu Nguyen ctx->remaining -= sizeof(src); 663062c8762SThu Nguyen assert(ctx->remaining >= 0); 664062c8762SThu Nguyen if (ctx->remaining < 0) { 665062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 666062c8762SThu Nguyen } 667062c8762SThu Nguyen 668062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 669062c8762SThu Nguyen ctx->cursor += sizeof(src); 670062c8762SThu Nguyen 671062c8762SThu Nguyen return PLDM_SUCCESS; 672062c8762SThu Nguyen } 673062c8762SThu Nguyen 674062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 67537dd6a3dSAndrew Jeffery _Generic((src), \ 67637dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 67737dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 67837dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 67937dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 68037dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 68137dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 682062c8762SThu Nguyen 683062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, 684062c8762SThu Nguyen const uint8_t *src, 685062c8762SThu Nguyen size_t count) 686062c8762SThu Nguyen { 687062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 688062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 689062c8762SThu Nguyen } 690062c8762SThu Nguyen 691062c8762SThu Nguyen if (!count) { 692062c8762SThu Nguyen return PLDM_SUCCESS; 693062c8762SThu Nguyen } 694062c8762SThu Nguyen 695a065eccbSAndrew Jeffery if (count >= SSIZE_MAX) { 696062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 697062c8762SThu Nguyen } 698062c8762SThu Nguyen 699a065eccbSAndrew Jeffery ctx->remaining -= (ssize_t)count; 700062c8762SThu Nguyen assert(ctx->remaining >= 0); 701062c8762SThu Nguyen if (ctx->remaining < 0) { 702062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 703062c8762SThu Nguyen } 704062c8762SThu Nguyen 705a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 706a065eccbSAndrew Jeffery ctx->cursor += count; 707062c8762SThu Nguyen 708062c8762SThu Nguyen return PLDM_SUCCESS; 709062c8762SThu Nguyen } 710062c8762SThu Nguyen 711062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 71237dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 71337dd6a3dSAndrew Jeffery count) 714062c8762SThu Nguyen 715062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, 716062c8762SThu Nguyen size_t required, void **cursor) 717062c8762SThu Nguyen { 718062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 719062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 720062c8762SThu Nguyen } 721062c8762SThu Nguyen 722062c8762SThu Nguyen if (required > SSIZE_MAX) { 723062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 724062c8762SThu Nguyen } 725062c8762SThu Nguyen 726062c8762SThu Nguyen ctx->remaining -= (ssize_t)required; 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 *cursor = ctx->cursor; 733062c8762SThu Nguyen ctx->cursor += required; 734062c8762SThu Nguyen 735062c8762SThu Nguyen return PLDM_SUCCESS; 736062c8762SThu Nguyen } 737062c8762SThu Nguyen 738062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, 739062c8762SThu Nguyen void **cursor, size_t *len) 740062c8762SThu Nguyen { 741062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 742062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 743062c8762SThu Nguyen } 744062c8762SThu Nguyen 745062c8762SThu Nguyen assert(ctx->remaining >= 0); 746062c8762SThu Nguyen if (ctx->remaining < 0) { 747062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 748062c8762SThu Nguyen } 749062c8762SThu Nguyen 750062c8762SThu Nguyen *cursor = ctx->cursor; 751062c8762SThu Nguyen ctx->cursor += ctx->remaining; 752062c8762SThu Nguyen *len = ctx->remaining; 753062c8762SThu Nguyen ctx->remaining = 0; 754062c8762SThu Nguyen 755062c8762SThu Nguyen return PLDM_SUCCESS; 756062c8762SThu Nguyen } 757c63f63a2SAndrew Jeffery #ifdef __cplusplus 758c63f63a2SAndrew Jeffery } 759c63f63a2SAndrew Jeffery #endif 760c63f63a2SAndrew Jeffery 761*66c7723aSAndrew Jeffery #ifdef __cplusplus 762*66c7723aSAndrew Jeffery #include <type_traits> 763*66c7723aSAndrew Jeffery 764*66c7723aSAndrew Jeffery template <typename T> 765*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 766*66c7723aSAndrew Jeffery void *buf) 767*66c7723aSAndrew Jeffery { 768*66c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 769*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 770*66c7723aSAndrew Jeffery } 771*66c7723aSAndrew Jeffery 772*66c7723aSAndrew Jeffery template <typename T> 773*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 774*66c7723aSAndrew Jeffery void *buf) 775*66c7723aSAndrew Jeffery { 776*66c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 777*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 778*66c7723aSAndrew Jeffery } 779*66c7723aSAndrew Jeffery 780*66c7723aSAndrew Jeffery template <typename T> 781*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 782*66c7723aSAndrew Jeffery void *buf) 783*66c7723aSAndrew Jeffery { 784*66c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 785*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 786*66c7723aSAndrew Jeffery } 787*66c7723aSAndrew Jeffery 788*66c7723aSAndrew Jeffery template <typename T> 789*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 790*66c7723aSAndrew Jeffery void *buf) 791*66c7723aSAndrew Jeffery { 792*66c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 793*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 794*66c7723aSAndrew Jeffery } 795*66c7723aSAndrew Jeffery 796*66c7723aSAndrew Jeffery template <typename T> 797*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 798*66c7723aSAndrew Jeffery void *buf) 799*66c7723aSAndrew Jeffery { 800*66c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 801*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 802*66c7723aSAndrew Jeffery } 803*66c7723aSAndrew Jeffery 804*66c7723aSAndrew Jeffery template <typename T> 805*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 806*66c7723aSAndrew Jeffery void *buf) 807*66c7723aSAndrew Jeffery { 808*66c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 809*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 810*66c7723aSAndrew Jeffery } 811*66c7723aSAndrew Jeffery 812*66c7723aSAndrew Jeffery template <typename T> 813*66c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 814*66c7723aSAndrew Jeffery void *buf) 815*66c7723aSAndrew Jeffery { 816*66c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 817*66c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 818*66c7723aSAndrew Jeffery } 819*66c7723aSAndrew Jeffery #endif 820*66c7723aSAndrew Jeffery 821c63f63a2SAndrew Jeffery #endif /* BUF_H */ 822