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> 49*c8df31c1SAndrew Jeffery #include <errno.h> 50c63f63a2SAndrew Jeffery #include <limits.h> 51c63f63a2SAndrew Jeffery #include <stdbool.h> 5266c7723aSAndrew Jeffery #include <stdint.h> 53c63f63a2SAndrew Jeffery #include <string.h> 54c63f63a2SAndrew Jeffery #include <sys/types.h> 55c63f63a2SAndrew Jeffery 562ff8cf89SAndrew Jeffery /* 572ff8cf89SAndrew Jeffery * We can't use static_assert() outside of some other C construct. Deal 582ff8cf89SAndrew Jeffery * with high-level global assertions by burying them in an unused struct 592ff8cf89SAndrew Jeffery * declaration, that has a sole member for compliance with the requirement that 602ff8cf89SAndrew Jeffery * types must have a size. 612ff8cf89SAndrew Jeffery */ 622ff8cf89SAndrew Jeffery static struct { 632ff8cf89SAndrew Jeffery static_assert( 642ff8cf89SAndrew Jeffery INTMAX_MAX != SIZE_MAX, 652ff8cf89SAndrew Jeffery "Extraction and insertion value comparisons may be broken"); 662ff8cf89SAndrew Jeffery static_assert(INTMAX_MIN + INTMAX_MAX <= 0, 672ff8cf89SAndrew Jeffery "Extraction and insertion arithmetic may be broken"); 68*c8df31c1SAndrew Jeffery static_assert(PLDM_SUCCESS == 0, "Error handling is broken"); 692ff8cf89SAndrew Jeffery int compliance; 702ff8cf89SAndrew Jeffery } build_assertions __attribute__((unused)); 712ff8cf89SAndrew Jeffery 72*c8df31c1SAndrew Jeffery enum pldm_msgbuf_error_mode { 73*c8df31c1SAndrew Jeffery PLDM_MSGBUF_PLDM_CC = 0x5a, 74*c8df31c1SAndrew Jeffery PLDM_MSGBUF_C_ERRNO = 0xa5, 75*c8df31c1SAndrew Jeffery }; 76*c8df31c1SAndrew Jeffery 77c63f63a2SAndrew Jeffery struct pldm_msgbuf { 78062c8762SThu Nguyen uint8_t *cursor; 792ff8cf89SAndrew Jeffery intmax_t remaining; 80*c8df31c1SAndrew Jeffery enum pldm_msgbuf_error_mode mode; 81c63f63a2SAndrew Jeffery }; 82c63f63a2SAndrew Jeffery 83*c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 84*c8df31c1SAndrew Jeffery pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err) 85*c8df31c1SAndrew Jeffery { 86*c8df31c1SAndrew Jeffery int rc; 87*c8df31c1SAndrew Jeffery 88*c8df31c1SAndrew Jeffery assert(err != 0); 89*c8df31c1SAndrew Jeffery assert(err <= INT_MAX); 90*c8df31c1SAndrew Jeffery 91*c8df31c1SAndrew Jeffery if (ctx->mode == PLDM_MSGBUF_C_ERRNO) { 92*c8df31c1SAndrew Jeffery if (err > INT_MAX) { 93*c8df31c1SAndrew Jeffery return -EINVAL; 94*c8df31c1SAndrew Jeffery } 95*c8df31c1SAndrew Jeffery 96*c8df31c1SAndrew Jeffery static_assert(INT_MIN + INT_MAX < 0, 97*c8df31c1SAndrew Jeffery "Arithmetic assumption failure"); 98*c8df31c1SAndrew Jeffery return -((int)err); 99*c8df31c1SAndrew Jeffery } 100*c8df31c1SAndrew Jeffery 101*c8df31c1SAndrew Jeffery if (err > INT_MAX) { 102*c8df31c1SAndrew Jeffery return PLDM_ERROR; 103*c8df31c1SAndrew Jeffery } 104*c8df31c1SAndrew Jeffery 105*c8df31c1SAndrew Jeffery assert(ctx->mode == PLDM_MSGBUF_PLDM_CC); 106*c8df31c1SAndrew Jeffery switch (err) { 107*c8df31c1SAndrew Jeffery case EINVAL: 108*c8df31c1SAndrew Jeffery rc = PLDM_ERROR_INVALID_DATA; 109*c8df31c1SAndrew Jeffery break; 110*c8df31c1SAndrew Jeffery case EBADMSG: 111*c8df31c1SAndrew Jeffery case EOVERFLOW: 112*c8df31c1SAndrew Jeffery rc = PLDM_ERROR_INVALID_LENGTH; 113*c8df31c1SAndrew Jeffery break; 114*c8df31c1SAndrew Jeffery default: 115*c8df31c1SAndrew Jeffery assert(false); 116*c8df31c1SAndrew Jeffery rc = PLDM_ERROR; 117*c8df31c1SAndrew Jeffery break; 118*c8df31c1SAndrew Jeffery } 119*c8df31c1SAndrew Jeffery 120*c8df31c1SAndrew Jeffery assert(rc > 0); 121*c8df31c1SAndrew Jeffery return rc; 122*c8df31c1SAndrew Jeffery } 123*c8df31c1SAndrew Jeffery 124c63f63a2SAndrew Jeffery /** 125c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 126c63f63a2SAndrew Jeffery * 127c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 128c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 129c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 130c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 131c63f63a2SAndrew Jeffery * 132*c8df31c1SAndrew Jeffery * @return 0 on success, otherwise an error code appropriate for the current 133*c8df31c1SAndrew Jeffery * personality. 134c63f63a2SAndrew Jeffery */ 13576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 136*c8df31c1SAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 137*c8df31c1SAndrew Jeffery pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 13876712f69SAndrew Jeffery size_t len) 139c63f63a2SAndrew Jeffery { 140*c8df31c1SAndrew Jeffery assert(ctx); 141*c8df31c1SAndrew Jeffery assert(ctx->mode == PLDM_MSGBUF_PLDM_CC || 142*c8df31c1SAndrew Jeffery ctx->mode == PLDM_MSGBUF_C_ERRNO); 143*c8df31c1SAndrew Jeffery 144*c8df31c1SAndrew Jeffery if (!buf) { 145*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 146c63f63a2SAndrew Jeffery } 147c63f63a2SAndrew Jeffery 1482ff8cf89SAndrew Jeffery if ((minsize > len)) { 149*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 150c63f63a2SAndrew Jeffery } 151c63f63a2SAndrew Jeffery 1522ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 1532ff8cf89SAndrew Jeffery if (len > INTMAX_MAX) { 154*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1552ff8cf89SAndrew Jeffery } 1562ff8cf89SAndrew Jeffery #endif 1572ff8cf89SAndrew Jeffery 15807febdbbSAndrew Jeffery if ((uintptr_t)buf + len < len) { 159*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 160c63f63a2SAndrew Jeffery } 161c63f63a2SAndrew Jeffery 162c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 1632ff8cf89SAndrew Jeffery ctx->remaining = (intmax_t)len; 164c63f63a2SAndrew Jeffery 165*c8df31c1SAndrew Jeffery return 0; 166*c8df31c1SAndrew Jeffery } 167*c8df31c1SAndrew Jeffery 168*c8df31c1SAndrew Jeffery /** 169*c8df31c1SAndrew Jeffery * @brief Initialise a msgbuf instance to return errors as PLDM completion codes 170*c8df31c1SAndrew Jeffery * 171*c8df31c1SAndrew Jeffery * @see pldm__msgbuf_init 172*c8df31c1SAndrew Jeffery * 173*c8df31c1SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 174*c8df31c1SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 175*c8df31c1SAndrew Jeffery * @param[in] buf - buffer to be extracted 176*c8df31c1SAndrew Jeffery * @param[in] len - size of buffer 177*c8df31c1SAndrew Jeffery * 178*c8df31c1SAndrew Jeffery * @return PLDM_SUCCESS if the provided buffer region is sensible, 179*c8df31c1SAndrew Jeffery * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, 180*c8df31c1SAndrew Jeffery * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 181*c8df31c1SAndrew Jeffery */ 182*c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 183*c8df31c1SAndrew Jeffery pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 184*c8df31c1SAndrew Jeffery size_t len) 185*c8df31c1SAndrew Jeffery { 186*c8df31c1SAndrew Jeffery if (!ctx) { 187*c8df31c1SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 188*c8df31c1SAndrew Jeffery } 189*c8df31c1SAndrew Jeffery 190*c8df31c1SAndrew Jeffery ctx->mode = PLDM_MSGBUF_PLDM_CC; 191*c8df31c1SAndrew Jeffery return pldm__msgbuf_init(ctx, minsize, buf, len); 192*c8df31c1SAndrew Jeffery } 193*c8df31c1SAndrew Jeffery 194*c8df31c1SAndrew Jeffery /** 195*c8df31c1SAndrew Jeffery * @brief Initialise a msgbuf instance to return errors as negative errno values 196*c8df31c1SAndrew Jeffery * 197*c8df31c1SAndrew Jeffery * @see pldm__msgbuf_init 198*c8df31c1SAndrew Jeffery * 199*c8df31c1SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 200*c8df31c1SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 201*c8df31c1SAndrew Jeffery * @param[in] buf - buffer to be extracted 202*c8df31c1SAndrew Jeffery * @param[in] len - size of buffer 203*c8df31c1SAndrew Jeffery * 204*c8df31c1SAndrew Jeffery * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if 205*c8df31c1SAndrew Jeffery * pointer parameters are invalid, or -EOVERFLOW if length constraints 206*c8df31c1SAndrew Jeffery * are violated. 207*c8df31c1SAndrew Jeffery */ 208*c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 209*c8df31c1SAndrew Jeffery pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 210*c8df31c1SAndrew Jeffery size_t len) 211*c8df31c1SAndrew Jeffery { 212*c8df31c1SAndrew Jeffery if (!ctx) { 213*c8df31c1SAndrew Jeffery return -EINVAL; 214*c8df31c1SAndrew Jeffery } 215*c8df31c1SAndrew Jeffery 216*c8df31c1SAndrew Jeffery ctx->mode = PLDM_MSGBUF_C_ERRNO; 217*c8df31c1SAndrew Jeffery return pldm__msgbuf_init(ctx, minsize, buf, len); 218c63f63a2SAndrew Jeffery } 219c63f63a2SAndrew Jeffery 220c63f63a2SAndrew Jeffery /** 221c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 222c63f63a2SAndrew Jeffery * 223c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 224c63f63a2SAndrew Jeffery * 225c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 226c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 227c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 228c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 229c63f63a2SAndrew Jeffery * pointer. 230c63f63a2SAndrew Jeffery */ 23176712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 23276712f69SAndrew Jeffery pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 233c63f63a2SAndrew Jeffery { 234*c8df31c1SAndrew Jeffery assert(ctx); 235*c8df31c1SAndrew Jeffery if (ctx->remaining < 0) { 236*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 237c63f63a2SAndrew Jeffery } 238c63f63a2SAndrew Jeffery 239*c8df31c1SAndrew Jeffery return 0; 240c63f63a2SAndrew Jeffery } 241c63f63a2SAndrew Jeffery 242c63f63a2SAndrew Jeffery /** 243db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 244db7b8324SAndrew Jeffery * 245db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 246db7b8324SAndrew Jeffery * 247db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 248db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 249db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 250db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 251db7b8324SAndrew Jeffery * pointer. 252db7b8324SAndrew Jeffery */ 25376712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 25476712f69SAndrew Jeffery pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 255db7b8324SAndrew Jeffery { 256*c8df31c1SAndrew Jeffery assert(ctx); 257*c8df31c1SAndrew Jeffery if (ctx->remaining != 0) { 258*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EBADMSG); 259db7b8324SAndrew Jeffery } 260db7b8324SAndrew Jeffery 261*c8df31c1SAndrew Jeffery return 0; 262db7b8324SAndrew Jeffery } 263db7b8324SAndrew Jeffery 264db7b8324SAndrew Jeffery /** 265c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 266c63f63a2SAndrew Jeffery * 267c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 268c63f63a2SAndrew Jeffery * 269c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 270c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 271c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 272c63f63a2SAndrew Jeffery * bounds of the buffer. 273c63f63a2SAndrew Jeffery */ 27476712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 27576712f69SAndrew Jeffery pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 276c63f63a2SAndrew Jeffery { 277c63f63a2SAndrew Jeffery int valid; 278c63f63a2SAndrew Jeffery 279*c8df31c1SAndrew Jeffery assert(ctx); 280c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 281c63f63a2SAndrew Jeffery 282c63f63a2SAndrew Jeffery ctx->cursor = NULL; 283c63f63a2SAndrew Jeffery ctx->remaining = 0; 284c63f63a2SAndrew Jeffery 285c63f63a2SAndrew Jeffery return valid; 286c63f63a2SAndrew Jeffery } 287c63f63a2SAndrew Jeffery 288c63f63a2SAndrew Jeffery /** 289db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 290db7b8324SAndrew Jeffery * has been completely consumed without overflow 291db7b8324SAndrew Jeffery * 292db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 293db7b8324SAndrew Jeffery * 294db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 295db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 296db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 297db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 298db7b8324SAndrew Jeffery */ 29976712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 30076712f69SAndrew Jeffery pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 301db7b8324SAndrew Jeffery { 302db7b8324SAndrew Jeffery int consumed; 303db7b8324SAndrew Jeffery 304*c8df31c1SAndrew Jeffery assert(ctx); 305db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 306db7b8324SAndrew Jeffery 307db7b8324SAndrew Jeffery ctx->cursor = NULL; 308db7b8324SAndrew Jeffery ctx->remaining = 0; 309db7b8324SAndrew Jeffery 310db7b8324SAndrew Jeffery return consumed; 311db7b8324SAndrew Jeffery } 312db7b8324SAndrew Jeffery 31366c7723aSAndrew Jeffery /* 31466c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 31566c7723aSAndrew Jeffery * 31666c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 31766c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 31866c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 31966c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 32066c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 32166c7723aSAndrew Jeffery * 32266c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 32366c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 32466c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 32566c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 32666c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 32766c7723aSAndrew Jeffery * 32866c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 32966c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 33066c7723aSAndrew Jeffery * constraints that cause some headaches: 33166c7723aSAndrew Jeffery * 33266c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 33366c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 33466c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 33566c7723aSAndrew Jeffery * 33666c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 33766c7723aSAndrew Jeffery * advantage of gtest. 33866c7723aSAndrew Jeffery * 33966c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 34066c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 34166c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 34266c7723aSAndrew Jeffery * 34366c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 34466c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 34566c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 34666c7723aSAndrew Jeffery * 34766c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 34866c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 34966c7723aSAndrew Jeffery * in C++. 35066c7723aSAndrew Jeffery * 35166c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 35266c7723aSAndrew Jeffery * 35366c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 35466c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 35566c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 35666c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 35766c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 35866c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 35966c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 36066c7723aSAndrew Jeffery * 36166c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 36266c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 36366c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 36466c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 36566c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 36666c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 36766c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 36866c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 36966c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 37066c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 37166c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 37266c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 37366c7723aSAndrew Jeffery * template argument per function. 37466c7723aSAndrew Jeffery * 37566c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 37666c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 37766c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 37866c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 37966c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 38066c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 38166c7723aSAndrew Jeffery * 38266c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 38366c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 38466c7723aSAndrew Jeffery * reasons: 38566c7723aSAndrew Jeffery * 38666c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 38766c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 38866c7723aSAndrew Jeffery * 38966c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 39066c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 39166c7723aSAndrew Jeffery */ 39266c7723aSAndrew Jeffery #ifdef __cplusplus 39366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 39466c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 39566c7723aSAndrew Jeffery #else 39666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 39766c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 39866c7723aSAndrew Jeffery #endif 39966c7723aSAndrew Jeffery 400db7b8324SAndrew Jeffery /** 401c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 402c63f63a2SAndrew Jeffery * 403c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 404c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 405c63f63a2SAndrew Jeffery * 406c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 407c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 408c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 409c63f63a2SAndrew Jeffery */ 41066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 41166c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 41266c7723aSAndrew Jeffery dst, ctx, dst) 41376712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 41466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 41576712f69SAndrew Jeffery pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 416c63f63a2SAndrew Jeffery { 417*c8df31c1SAndrew Jeffery assert(ctx); 418*c8df31c1SAndrew Jeffery 419*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 420*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 421c63f63a2SAndrew Jeffery } 422c63f63a2SAndrew Jeffery 4232ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 4242ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 425*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 4262ff8cf89SAndrew Jeffery } 42766c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 428c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 429c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 430*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 431c63f63a2SAndrew Jeffery } 432c63f63a2SAndrew Jeffery 43366c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 43466c7723aSAndrew Jeffery 435c63f63a2SAndrew Jeffery ctx->cursor++; 436*c8df31c1SAndrew Jeffery return 0; 437c63f63a2SAndrew Jeffery } 438c63f63a2SAndrew Jeffery 43966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 44066c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 44166c7723aSAndrew Jeffery ctx, dst) 44276712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 44366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 44476712f69SAndrew Jeffery pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 445c63f63a2SAndrew Jeffery { 446*c8df31c1SAndrew Jeffery assert(ctx); 447*c8df31c1SAndrew Jeffery 448*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 449*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 450c63f63a2SAndrew Jeffery } 451c63f63a2SAndrew Jeffery 4522ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 4532ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 454*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 4552ff8cf89SAndrew Jeffery } 45666c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 457c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 458c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 459*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 460c63f63a2SAndrew Jeffery } 461c63f63a2SAndrew Jeffery 46266c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 463c63f63a2SAndrew Jeffery ctx->cursor++; 464*c8df31c1SAndrew Jeffery return 0; 465c63f63a2SAndrew Jeffery } 466c63f63a2SAndrew Jeffery 46766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 46866c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 46966c7723aSAndrew Jeffery dst, ctx, dst) 47076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 47166c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 47276712f69SAndrew Jeffery pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst) 473c63f63a2SAndrew Jeffery { 474c63f63a2SAndrew Jeffery uint16_t ldst; 475c63f63a2SAndrew Jeffery 476*c8df31c1SAndrew Jeffery assert(ctx); 477*c8df31c1SAndrew Jeffery 478*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 479*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 480c63f63a2SAndrew Jeffery } 481c63f63a2SAndrew Jeffery 4822ff8cf89SAndrew Jeffery // Check for underflow while tracking the magnitude of the buffer overflow 4832ff8cf89SAndrew Jeffery static_assert( 4842ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 4852ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 4862ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 4872ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 4882ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 489*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 4902ff8cf89SAndrew Jeffery } 4912ff8cf89SAndrew Jeffery 492c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 493c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 494c63f63a2SAndrew Jeffery // we've overflowed. 495c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 496c63f63a2SAndrew Jeffery 497c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 498c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 499c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 500c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 501c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 502*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 503c63f63a2SAndrew Jeffery } 504c63f63a2SAndrew Jeffery 505c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 506c63f63a2SAndrew Jeffery // issues on the target architecture 507c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 508c63f63a2SAndrew Jeffery 509c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 51066c7723aSAndrew Jeffery ldst = le16toh(ldst); 51166c7723aSAndrew Jeffery 51266c7723aSAndrew Jeffery // Allow storing to unaligned 51366c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 51466c7723aSAndrew Jeffery 515c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 516c63f63a2SAndrew Jeffery 517*c8df31c1SAndrew Jeffery return 0; 518c63f63a2SAndrew Jeffery } 519c63f63a2SAndrew Jeffery 52066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 52166c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 52266c7723aSAndrew Jeffery dst, ctx, dst) 52376712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 52466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 52576712f69SAndrew Jeffery pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 526c63f63a2SAndrew Jeffery { 527c63f63a2SAndrew Jeffery int16_t ldst; 528c63f63a2SAndrew Jeffery 529*c8df31c1SAndrew Jeffery assert(ctx); 530*c8df31c1SAndrew Jeffery 531*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 532*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 533c63f63a2SAndrew Jeffery } 534c63f63a2SAndrew Jeffery 5352ff8cf89SAndrew Jeffery static_assert( 5362ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5372ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5382ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5392ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5402ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 541*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 5422ff8cf89SAndrew Jeffery } 543c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 544c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 545c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 546*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 547c63f63a2SAndrew Jeffery } 548c63f63a2SAndrew Jeffery 549c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 550c63f63a2SAndrew Jeffery 55166c7723aSAndrew Jeffery ldst = le16toh(ldst); 55266c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 553c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 554c63f63a2SAndrew Jeffery 555*c8df31c1SAndrew Jeffery return 0; 556c63f63a2SAndrew Jeffery } 557c63f63a2SAndrew Jeffery 55866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 55966c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 56066c7723aSAndrew Jeffery dst, ctx, dst) 56176712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 56266c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 56376712f69SAndrew Jeffery pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst) 564c63f63a2SAndrew Jeffery { 565c63f63a2SAndrew Jeffery uint32_t ldst; 566c63f63a2SAndrew Jeffery 567*c8df31c1SAndrew Jeffery assert(ctx); 568*c8df31c1SAndrew Jeffery 569*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 570*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 571c63f63a2SAndrew Jeffery } 572c63f63a2SAndrew Jeffery 5732ff8cf89SAndrew Jeffery static_assert( 5742ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5752ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5762ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5772ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5782ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 579*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 5802ff8cf89SAndrew Jeffery } 581c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 582c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 583c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 584*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 585c63f63a2SAndrew Jeffery } 586c63f63a2SAndrew Jeffery 587c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 58866c7723aSAndrew Jeffery ldst = le32toh(ldst); 58966c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 590c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 591c63f63a2SAndrew Jeffery 592*c8df31c1SAndrew Jeffery return 0; 593c63f63a2SAndrew Jeffery } 594c63f63a2SAndrew Jeffery 59566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 59666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 59766c7723aSAndrew Jeffery dst, ctx, dst) 59876712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 59966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 60076712f69SAndrew Jeffery pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 601c63f63a2SAndrew Jeffery { 602c63f63a2SAndrew Jeffery int32_t ldst; 603c63f63a2SAndrew Jeffery 604*c8df31c1SAndrew Jeffery assert(ctx); 605*c8df31c1SAndrew Jeffery 606*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 607*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 608c63f63a2SAndrew Jeffery } 609c63f63a2SAndrew Jeffery 6102ff8cf89SAndrew Jeffery static_assert( 6112ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6122ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 6132ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6142ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 6152ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 616*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 6172ff8cf89SAndrew Jeffery } 618c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 619c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 620c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 621*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 622c63f63a2SAndrew Jeffery } 623c63f63a2SAndrew Jeffery 624c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 62566c7723aSAndrew Jeffery ldst = le32toh(ldst); 62666c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 627c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 628c63f63a2SAndrew Jeffery 629c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 630c63f63a2SAndrew Jeffery } 631c63f63a2SAndrew Jeffery 63266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst) \ 63366c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 63466c7723aSAndrew Jeffery dst, ctx, dst) 63576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 63666c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 63776712f69SAndrew Jeffery pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst) 638c63f63a2SAndrew Jeffery { 639c63f63a2SAndrew Jeffery uint32_t ldst; 640c63f63a2SAndrew Jeffery 641*c8df31c1SAndrew Jeffery static_assert(sizeof(real32_t) == sizeof(ldst), 64266c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 64366c7723aSAndrew Jeffery 644*c8df31c1SAndrew Jeffery assert(ctx); 645*c8df31c1SAndrew Jeffery 646*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 647*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 648c63f63a2SAndrew Jeffery } 649c63f63a2SAndrew Jeffery 6502ff8cf89SAndrew Jeffery static_assert( 6512ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6522ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 6532ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6542ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 6552ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 656*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 6572ff8cf89SAndrew Jeffery } 658c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 659c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 660c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 661*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 662c63f63a2SAndrew Jeffery } 663c63f63a2SAndrew Jeffery 664c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 665c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 66666c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 66766c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 668c63f63a2SAndrew Jeffery 669*c8df31c1SAndrew Jeffery return 0; 670c63f63a2SAndrew Jeffery } 671c63f63a2SAndrew Jeffery 67266c7723aSAndrew Jeffery /** 67366c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 67466c7723aSAndrew Jeffery * 67566c7723aSAndrew Jeffery * @param ctx The msgbuf context object 67666c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 67766c7723aSAndrew Jeffery * extracted 67866c7723aSAndrew Jeffery * 67966c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 68066c7723aSAndrew Jeffery */ 681c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 68266c7723aSAndrew Jeffery _Generic((dst), \ 68366c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 68466c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 68566c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 68666c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 68766c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 68866c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 68966c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 69066c7723aSAndrew Jeffery 69166c7723aSAndrew Jeffery /** 69266c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 69366c7723aSAndrew Jeffery * 69466c7723aSAndrew Jeffery * @param ctx The msgbuf context object 69566c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 69666c7723aSAndrew Jeffery * cursor should be extracted 69766c7723aSAndrew Jeffery * 69866c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 69966c7723aSAndrew Jeffery */ 70066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 70166c7723aSAndrew Jeffery _Generic((dst), \ 70266c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 70366c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 70466c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 70566c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 70666c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 70766c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 70866c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 709c63f63a2SAndrew Jeffery 71076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 71176712f69SAndrew Jeffery pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst, 71276712f69SAndrew Jeffery size_t count) 713369b121aSAndrew Jeffery { 714*c8df31c1SAndrew Jeffery assert(ctx); 715*c8df31c1SAndrew Jeffery 716*c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 717*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 718369b121aSAndrew Jeffery } 719369b121aSAndrew Jeffery 720369b121aSAndrew Jeffery if (!count) { 721*c8df31c1SAndrew Jeffery return 0; 722369b121aSAndrew Jeffery } 723369b121aSAndrew Jeffery 7242ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 7252ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 726*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 727369b121aSAndrew Jeffery } 7282ff8cf89SAndrew Jeffery #endif 729369b121aSAndrew Jeffery 7302ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 731*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 7322ff8cf89SAndrew Jeffery } 7332ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 734369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 735369b121aSAndrew Jeffery if (ctx->remaining < 0) { 736*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 737369b121aSAndrew Jeffery } 738369b121aSAndrew Jeffery 739a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 740a065eccbSAndrew Jeffery ctx->cursor += count; 741369b121aSAndrew Jeffery 742*c8df31c1SAndrew Jeffery return 0; 743369b121aSAndrew Jeffery } 744369b121aSAndrew Jeffery 745369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 74637dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 74737dd6a3dSAndrew Jeffery count) 748369b121aSAndrew Jeffery 74976712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 75076712f69SAndrew Jeffery pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src) 751062c8762SThu Nguyen { 752062c8762SThu Nguyen uint32_t val = htole32(src); 753062c8762SThu Nguyen 754*c8df31c1SAndrew Jeffery assert(ctx); 755*c8df31c1SAndrew Jeffery 756*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 757*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 758062c8762SThu Nguyen } 759062c8762SThu Nguyen 7602ff8cf89SAndrew Jeffery static_assert( 7612ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7622ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7632ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7642ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7652ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 766*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 7672ff8cf89SAndrew Jeffery } 768062c8762SThu Nguyen ctx->remaining -= sizeof(src); 769062c8762SThu Nguyen assert(ctx->remaining >= 0); 770062c8762SThu Nguyen if (ctx->remaining < 0) { 771*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 772062c8762SThu Nguyen } 773062c8762SThu Nguyen 774062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 775062c8762SThu Nguyen ctx->cursor += sizeof(src); 776062c8762SThu Nguyen 777*c8df31c1SAndrew Jeffery return 0; 778062c8762SThu Nguyen } 779062c8762SThu Nguyen 78076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 78176712f69SAndrew Jeffery pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src) 782062c8762SThu Nguyen { 783062c8762SThu Nguyen uint16_t val = htole16(src); 784062c8762SThu Nguyen 785*c8df31c1SAndrew Jeffery assert(ctx); 786*c8df31c1SAndrew Jeffery 787*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 788*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 789062c8762SThu Nguyen } 790062c8762SThu Nguyen 7912ff8cf89SAndrew Jeffery static_assert( 7922ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7932ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7942ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7952ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7962ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 797*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 7982ff8cf89SAndrew Jeffery } 799062c8762SThu Nguyen ctx->remaining -= sizeof(src); 800062c8762SThu Nguyen assert(ctx->remaining >= 0); 801062c8762SThu Nguyen if (ctx->remaining < 0) { 802*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 803062c8762SThu Nguyen } 804062c8762SThu Nguyen 805062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 806062c8762SThu Nguyen ctx->cursor += sizeof(src); 807062c8762SThu Nguyen 808*c8df31c1SAndrew Jeffery return 0; 809062c8762SThu Nguyen } 810062c8762SThu Nguyen 81176712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 81276712f69SAndrew Jeffery pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src) 813062c8762SThu Nguyen { 814*c8df31c1SAndrew Jeffery assert(ctx); 815*c8df31c1SAndrew Jeffery 816*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 817*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 818062c8762SThu Nguyen } 819062c8762SThu Nguyen 8202ff8cf89SAndrew Jeffery static_assert( 8212ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8222ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8232ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8242ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8252ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 826*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8272ff8cf89SAndrew Jeffery } 828062c8762SThu Nguyen ctx->remaining -= sizeof(src); 829062c8762SThu Nguyen assert(ctx->remaining >= 0); 830062c8762SThu Nguyen if (ctx->remaining < 0) { 831*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 832062c8762SThu Nguyen } 833062c8762SThu Nguyen 834062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 835062c8762SThu Nguyen ctx->cursor += sizeof(src); 836062c8762SThu Nguyen 837*c8df31c1SAndrew Jeffery return 0; 838062c8762SThu Nguyen } 839062c8762SThu Nguyen 84076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 84176712f69SAndrew Jeffery pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src) 842062c8762SThu Nguyen { 843062c8762SThu Nguyen int32_t val = htole32(src); 844062c8762SThu Nguyen 845*c8df31c1SAndrew Jeffery assert(ctx); 846*c8df31c1SAndrew Jeffery 847*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 848*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 849062c8762SThu Nguyen } 850062c8762SThu Nguyen 8512ff8cf89SAndrew Jeffery static_assert( 8522ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8532ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8542ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8552ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8562ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 857*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8582ff8cf89SAndrew Jeffery } 859062c8762SThu Nguyen ctx->remaining -= sizeof(src); 860062c8762SThu Nguyen assert(ctx->remaining >= 0); 861062c8762SThu Nguyen if (ctx->remaining < 0) { 862*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 863062c8762SThu Nguyen } 864062c8762SThu Nguyen 865062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 866062c8762SThu Nguyen ctx->cursor += sizeof(src); 867062c8762SThu Nguyen 868*c8df31c1SAndrew Jeffery return 0; 869062c8762SThu Nguyen } 870062c8762SThu Nguyen 87176712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 87276712f69SAndrew Jeffery pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src) 873062c8762SThu Nguyen { 874062c8762SThu Nguyen int16_t val = htole16(src); 875062c8762SThu Nguyen 876*c8df31c1SAndrew Jeffery assert(ctx); 877*c8df31c1SAndrew Jeffery 878*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 879*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 880062c8762SThu Nguyen } 881062c8762SThu Nguyen 8822ff8cf89SAndrew Jeffery static_assert( 8832ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8842ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8852ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8862ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8872ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 888*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8892ff8cf89SAndrew Jeffery } 890062c8762SThu Nguyen ctx->remaining -= sizeof(src); 891062c8762SThu Nguyen assert(ctx->remaining >= 0); 892062c8762SThu Nguyen if (ctx->remaining < 0) { 893*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 894062c8762SThu Nguyen } 895062c8762SThu Nguyen 896062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 897062c8762SThu Nguyen ctx->cursor += sizeof(src); 898062c8762SThu Nguyen 899*c8df31c1SAndrew Jeffery return 0; 900062c8762SThu Nguyen } 901062c8762SThu Nguyen 90276712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 90376712f69SAndrew Jeffery pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src) 904062c8762SThu Nguyen { 905*c8df31c1SAndrew Jeffery assert(ctx); 906*c8df31c1SAndrew Jeffery 907*c8df31c1SAndrew Jeffery if (!ctx->cursor) { 908*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 909062c8762SThu Nguyen } 910062c8762SThu Nguyen 9112ff8cf89SAndrew Jeffery static_assert( 9122ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 9132ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 9142ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 9152ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 9162ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 917*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9182ff8cf89SAndrew Jeffery } 919062c8762SThu Nguyen ctx->remaining -= sizeof(src); 920062c8762SThu Nguyen assert(ctx->remaining >= 0); 921062c8762SThu Nguyen if (ctx->remaining < 0) { 922*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 923062c8762SThu Nguyen } 924062c8762SThu Nguyen 925062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 926062c8762SThu Nguyen ctx->cursor += sizeof(src); 927062c8762SThu Nguyen 928*c8df31c1SAndrew Jeffery return 0; 929062c8762SThu Nguyen } 930062c8762SThu Nguyen 931062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 93237dd6a3dSAndrew Jeffery _Generic((src), \ 93337dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 93437dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 93537dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 93637dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 93737dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 93837dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 939062c8762SThu Nguyen 94076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 94176712f69SAndrew Jeffery pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src, 942062c8762SThu Nguyen size_t count) 943062c8762SThu Nguyen { 944*c8df31c1SAndrew Jeffery assert(ctx); 945*c8df31c1SAndrew Jeffery 946*c8df31c1SAndrew Jeffery if (!ctx->cursor || !src) { 947*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 948062c8762SThu Nguyen } 949062c8762SThu Nguyen 950062c8762SThu Nguyen if (!count) { 951*c8df31c1SAndrew Jeffery return 0; 952062c8762SThu Nguyen } 953062c8762SThu Nguyen 9542ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 9552ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 956*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 957062c8762SThu Nguyen } 9582ff8cf89SAndrew Jeffery #endif 959062c8762SThu Nguyen 9602ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 961*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9622ff8cf89SAndrew Jeffery } 9632ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 964062c8762SThu Nguyen assert(ctx->remaining >= 0); 965062c8762SThu Nguyen if (ctx->remaining < 0) { 966*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 967062c8762SThu Nguyen } 968062c8762SThu Nguyen 969a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 970a065eccbSAndrew Jeffery ctx->cursor += count; 971062c8762SThu Nguyen 972*c8df31c1SAndrew Jeffery return 0; 973062c8762SThu Nguyen } 974062c8762SThu Nguyen 975062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 97637dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 97737dd6a3dSAndrew Jeffery count) 978062c8762SThu Nguyen 97976712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 98076712f69SAndrew Jeffery pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required, 98176712f69SAndrew Jeffery void **cursor) 982062c8762SThu Nguyen { 983*c8df31c1SAndrew Jeffery assert(ctx); 984*c8df31c1SAndrew Jeffery 985*c8df31c1SAndrew Jeffery if (!ctx->cursor || !cursor || *cursor) { 986*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 987062c8762SThu Nguyen } 988062c8762SThu Nguyen 9892ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 9902ff8cf89SAndrew Jeffery if (required > INTMAX_MAX) { 991*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 992062c8762SThu Nguyen } 9932ff8cf89SAndrew Jeffery #endif 994062c8762SThu Nguyen 9952ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)required) { 996*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9972ff8cf89SAndrew Jeffery } 9982ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)required; 999062c8762SThu Nguyen assert(ctx->remaining >= 0); 1000062c8762SThu Nguyen if (ctx->remaining < 0) { 1001*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1002062c8762SThu Nguyen } 1003062c8762SThu Nguyen 1004062c8762SThu Nguyen *cursor = ctx->cursor; 1005062c8762SThu Nguyen ctx->cursor += required; 1006062c8762SThu Nguyen 1007*c8df31c1SAndrew Jeffery return 0; 1008062c8762SThu Nguyen } 1009062c8762SThu Nguyen 101076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 101176712f69SAndrew Jeffery pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len) 1012062c8762SThu Nguyen { 1013*c8df31c1SAndrew Jeffery assert(ctx); 1014*c8df31c1SAndrew Jeffery 1015*c8df31c1SAndrew Jeffery if (!ctx->cursor || !cursor || *cursor || !len) { 1016*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 1017062c8762SThu Nguyen } 1018062c8762SThu Nguyen 1019062c8762SThu Nguyen assert(ctx->remaining >= 0); 1020062c8762SThu Nguyen if (ctx->remaining < 0) { 1021*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1022062c8762SThu Nguyen } 1023062c8762SThu Nguyen 1024062c8762SThu Nguyen *cursor = ctx->cursor; 1025062c8762SThu Nguyen ctx->cursor += ctx->remaining; 1026062c8762SThu Nguyen *len = ctx->remaining; 1027062c8762SThu Nguyen ctx->remaining = 0; 1028062c8762SThu Nguyen 1029*c8df31c1SAndrew Jeffery return 0; 1030062c8762SThu Nguyen } 1031909bf7c2SVarsha Kaverappa 1032909bf7c2SVarsha Kaverappa /** 1033909bf7c2SVarsha Kaverappa * @brief pldm_msgbuf copy data between two msg buffers 1034909bf7c2SVarsha Kaverappa * 1035909bf7c2SVarsha Kaverappa * @param[inout] src - pldm_msgbuf for source from where value should be copied 1036909bf7c2SVarsha Kaverappa * @param[inout] dst - destination of copy from source 1037909bf7c2SVarsha Kaverappa * @param[in] size - size of data to be copied 1038909bf7c2SVarsha Kaverappa * @param[in] description - description of data copied 1039909bf7c2SVarsha Kaverappa * 1040909bf7c2SVarsha Kaverappa * @return PLDM_SUCCESS if buffer accesses were in-bounds, 1041909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_LENGTH otherwise. 1042909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_DATA if input is invalid 1043909bf7c2SVarsha Kaverappa */ 1044909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name) \ 1045909bf7c2SVarsha Kaverappa pldm__msgbuf_copy(dst, src, sizeof(type), #name) 104676712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 1047909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 104876712f69SAndrew Jeffery pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size, 1049909bf7c2SVarsha Kaverappa const char *description) 1050909bf7c2SVarsha Kaverappa { 1051*c8df31c1SAndrew Jeffery assert(src); 1052*c8df31c1SAndrew Jeffery assert(dst); 1053*c8df31c1SAndrew Jeffery assert(src->mode == dst->mode); 1054*c8df31c1SAndrew Jeffery 1055*c8df31c1SAndrew Jeffery if (!src->cursor || !dst->cursor || !description) { 1056*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EINVAL); 1057909bf7c2SVarsha Kaverappa } 1058909bf7c2SVarsha Kaverappa 1059909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX 1060909bf7c2SVarsha Kaverappa if (size > INTMAX_MAX) { 1061*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1062909bf7c2SVarsha Kaverappa } 1063909bf7c2SVarsha Kaverappa #endif 1064909bf7c2SVarsha Kaverappa 1065909bf7c2SVarsha Kaverappa if (src->remaining < INTMAX_MIN + (intmax_t)size) { 1066*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1067909bf7c2SVarsha Kaverappa } 1068909bf7c2SVarsha Kaverappa 1069909bf7c2SVarsha Kaverappa if (dst->remaining < INTMAX_MIN + (intmax_t)size) { 1070*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1071909bf7c2SVarsha Kaverappa } 1072909bf7c2SVarsha Kaverappa 1073909bf7c2SVarsha Kaverappa src->remaining -= (intmax_t)size; 1074909bf7c2SVarsha Kaverappa assert(src->remaining >= 0); 1075909bf7c2SVarsha Kaverappa if (src->remaining < 0) { 1076*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1077909bf7c2SVarsha Kaverappa } 1078909bf7c2SVarsha Kaverappa 1079909bf7c2SVarsha Kaverappa dst->remaining -= (intmax_t)size; 1080909bf7c2SVarsha Kaverappa assert(dst->remaining >= 0); 1081909bf7c2SVarsha Kaverappa if (dst->remaining < 0) { 1082*c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1083909bf7c2SVarsha Kaverappa } 1084909bf7c2SVarsha Kaverappa 1085909bf7c2SVarsha Kaverappa memcpy(dst->cursor, src->cursor, size); 1086909bf7c2SVarsha Kaverappa src->cursor += size; 1087909bf7c2SVarsha Kaverappa dst->cursor += size; 1088909bf7c2SVarsha Kaverappa 1089*c8df31c1SAndrew Jeffery return 0; 1090909bf7c2SVarsha Kaverappa } 1091*c8df31c1SAndrew Jeffery 1092c63f63a2SAndrew Jeffery #ifdef __cplusplus 1093c63f63a2SAndrew Jeffery } 1094c63f63a2SAndrew Jeffery #endif 1095c63f63a2SAndrew Jeffery 109666c7723aSAndrew Jeffery #ifdef __cplusplus 109766c7723aSAndrew Jeffery #include <type_traits> 109866c7723aSAndrew Jeffery 109966c7723aSAndrew Jeffery template <typename T> 110066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 110166c7723aSAndrew Jeffery void *buf) 110266c7723aSAndrew Jeffery { 110366c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 110466c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 110566c7723aSAndrew Jeffery } 110666c7723aSAndrew Jeffery 110766c7723aSAndrew Jeffery template <typename T> 110866c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 110966c7723aSAndrew Jeffery void *buf) 111066c7723aSAndrew Jeffery { 111166c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 111266c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 111366c7723aSAndrew Jeffery } 111466c7723aSAndrew Jeffery 111566c7723aSAndrew Jeffery template <typename T> 111666c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 111766c7723aSAndrew Jeffery void *buf) 111866c7723aSAndrew Jeffery { 111966c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 112066c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 112166c7723aSAndrew Jeffery } 112266c7723aSAndrew Jeffery 112366c7723aSAndrew Jeffery template <typename T> 112466c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 112566c7723aSAndrew Jeffery void *buf) 112666c7723aSAndrew Jeffery { 112766c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 112866c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 112966c7723aSAndrew Jeffery } 113066c7723aSAndrew Jeffery 113166c7723aSAndrew Jeffery template <typename T> 113266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 113366c7723aSAndrew Jeffery void *buf) 113466c7723aSAndrew Jeffery { 113566c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 113666c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 113766c7723aSAndrew Jeffery } 113866c7723aSAndrew Jeffery 113966c7723aSAndrew Jeffery template <typename T> 114066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 114166c7723aSAndrew Jeffery void *buf) 114266c7723aSAndrew Jeffery { 114366c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 114466c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 114566c7723aSAndrew Jeffery } 114666c7723aSAndrew Jeffery 114766c7723aSAndrew Jeffery template <typename T> 114866c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 114966c7723aSAndrew Jeffery void *buf) 115066c7723aSAndrew Jeffery { 115166c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 115266c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 115366c7723aSAndrew Jeffery } 115466c7723aSAndrew Jeffery #endif 115566c7723aSAndrew Jeffery 1156c63f63a2SAndrew Jeffery #endif /* BUF_H */ 1157