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> 49c8df31c1SAndrew 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"); 68c8df31c1SAndrew Jeffery static_assert(PLDM_SUCCESS == 0, "Error handling is broken"); 692ff8cf89SAndrew Jeffery int compliance; 702ff8cf89SAndrew Jeffery } build_assertions __attribute__((unused)); 712ff8cf89SAndrew Jeffery 72c8df31c1SAndrew Jeffery enum pldm_msgbuf_error_mode { 73c8df31c1SAndrew Jeffery PLDM_MSGBUF_PLDM_CC = 0x5a, 74c8df31c1SAndrew Jeffery PLDM_MSGBUF_C_ERRNO = 0xa5, 75c8df31c1SAndrew Jeffery }; 76c8df31c1SAndrew Jeffery 77c63f63a2SAndrew Jeffery struct pldm_msgbuf { 78062c8762SThu Nguyen uint8_t *cursor; 792ff8cf89SAndrew Jeffery intmax_t remaining; 80c8df31c1SAndrew Jeffery enum pldm_msgbuf_error_mode mode; 81c63f63a2SAndrew Jeffery }; 82c63f63a2SAndrew Jeffery 83*d861a681SAndrew Jeffery /** 84*d861a681SAndrew Jeffery * @brief Either negate an errno value or return a value mapped to a PLDM 85*d861a681SAndrew Jeffery * completion code. 86*d861a681SAndrew Jeffery * 87*d861a681SAndrew Jeffery * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API 88*d861a681SAndrew Jeffery * for ergonomics. It's preferred that we don't try to unify this with 89*d861a681SAndrew Jeffery * `pldm_xlate_errno()` from src/api.h despite the similarities. 90*d861a681SAndrew Jeffery * 91*d861a681SAndrew Jeffery * @param[in] ctx - The msgbuf context providing the personality info 92*d861a681SAndrew Jeffery * @param[in] err - The positive errno value to translate 93*d861a681SAndrew Jeffery * 94*d861a681SAndrew Jeffery * @return Either the negated value of @p err if the context's error mode is 95*d861a681SAndrew Jeffery * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the 96*d861a681SAndrew Jeffery * error mode is `PLDM_MSGBUF_PLDM_CC`. 97*d861a681SAndrew Jeffery */ 98c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 99c8df31c1SAndrew Jeffery pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err) 100c8df31c1SAndrew Jeffery { 101c8df31c1SAndrew Jeffery int rc; 102c8df31c1SAndrew Jeffery 103c8df31c1SAndrew Jeffery assert(err != 0); 104c8df31c1SAndrew Jeffery assert(err <= INT_MAX); 105c8df31c1SAndrew Jeffery 106c8df31c1SAndrew Jeffery if (ctx->mode == PLDM_MSGBUF_C_ERRNO) { 107c8df31c1SAndrew Jeffery if (err > INT_MAX) { 108c8df31c1SAndrew Jeffery return -EINVAL; 109c8df31c1SAndrew Jeffery } 110c8df31c1SAndrew Jeffery 111c8df31c1SAndrew Jeffery static_assert(INT_MIN + INT_MAX < 0, 112c8df31c1SAndrew Jeffery "Arithmetic assumption failure"); 113c8df31c1SAndrew Jeffery return -((int)err); 114c8df31c1SAndrew Jeffery } 115c8df31c1SAndrew Jeffery 116c8df31c1SAndrew Jeffery if (err > INT_MAX) { 117c8df31c1SAndrew Jeffery return PLDM_ERROR; 118c8df31c1SAndrew Jeffery } 119c8df31c1SAndrew Jeffery 120c8df31c1SAndrew Jeffery assert(ctx->mode == PLDM_MSGBUF_PLDM_CC); 121c8df31c1SAndrew Jeffery switch (err) { 122c8df31c1SAndrew Jeffery case EINVAL: 123c8df31c1SAndrew Jeffery rc = PLDM_ERROR_INVALID_DATA; 124c8df31c1SAndrew Jeffery break; 125c8df31c1SAndrew Jeffery case EBADMSG: 126c8df31c1SAndrew Jeffery case EOVERFLOW: 127c8df31c1SAndrew Jeffery rc = PLDM_ERROR_INVALID_LENGTH; 128c8df31c1SAndrew Jeffery break; 129c8df31c1SAndrew Jeffery default: 130c8df31c1SAndrew Jeffery assert(false); 131c8df31c1SAndrew Jeffery rc = PLDM_ERROR; 132c8df31c1SAndrew Jeffery break; 133c8df31c1SAndrew Jeffery } 134c8df31c1SAndrew Jeffery 135c8df31c1SAndrew Jeffery assert(rc > 0); 136c8df31c1SAndrew Jeffery return rc; 137c8df31c1SAndrew Jeffery } 138c8df31c1SAndrew Jeffery 139c63f63a2SAndrew Jeffery /** 140c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 141c63f63a2SAndrew Jeffery * 142c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 143c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 144c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 145c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 146c63f63a2SAndrew Jeffery * 147c8df31c1SAndrew Jeffery * @return 0 on success, otherwise an error code appropriate for the current 148c8df31c1SAndrew Jeffery * personality. 149c63f63a2SAndrew Jeffery */ 15076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 151c8df31c1SAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 152c8df31c1SAndrew Jeffery pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 15376712f69SAndrew Jeffery size_t len) 154c63f63a2SAndrew Jeffery { 155c8df31c1SAndrew Jeffery assert(ctx); 156c8df31c1SAndrew Jeffery assert(ctx->mode == PLDM_MSGBUF_PLDM_CC || 157c8df31c1SAndrew Jeffery ctx->mode == PLDM_MSGBUF_C_ERRNO); 158c8df31c1SAndrew Jeffery 159c8df31c1SAndrew Jeffery if (!buf) { 160c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 161c63f63a2SAndrew Jeffery } 162c63f63a2SAndrew Jeffery 1632ff8cf89SAndrew Jeffery if ((minsize > len)) { 164c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 165c63f63a2SAndrew Jeffery } 166c63f63a2SAndrew Jeffery 1672ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 1682ff8cf89SAndrew Jeffery if (len > INTMAX_MAX) { 169c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1702ff8cf89SAndrew Jeffery } 1712ff8cf89SAndrew Jeffery #endif 1722ff8cf89SAndrew Jeffery 17307febdbbSAndrew Jeffery if ((uintptr_t)buf + len < len) { 174c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 175c63f63a2SAndrew Jeffery } 176c63f63a2SAndrew Jeffery 177c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 1782ff8cf89SAndrew Jeffery ctx->remaining = (intmax_t)len; 179c63f63a2SAndrew Jeffery 180c8df31c1SAndrew Jeffery return 0; 181c8df31c1SAndrew Jeffery } 182c8df31c1SAndrew Jeffery 183c8df31c1SAndrew Jeffery /** 184c8df31c1SAndrew Jeffery * @brief Initialise a msgbuf instance to return errors as PLDM completion codes 185c8df31c1SAndrew Jeffery * 186c8df31c1SAndrew Jeffery * @see pldm__msgbuf_init 187c8df31c1SAndrew Jeffery * 188c8df31c1SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 189c8df31c1SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 190c8df31c1SAndrew Jeffery * @param[in] buf - buffer to be extracted 191c8df31c1SAndrew Jeffery * @param[in] len - size of buffer 192c8df31c1SAndrew Jeffery * 193c8df31c1SAndrew Jeffery * @return PLDM_SUCCESS if the provided buffer region is sensible, 194c8df31c1SAndrew Jeffery * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, 195c8df31c1SAndrew Jeffery * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 196c8df31c1SAndrew Jeffery */ 197c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 198c8df31c1SAndrew Jeffery pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 199c8df31c1SAndrew Jeffery size_t len) 200c8df31c1SAndrew Jeffery { 201c8df31c1SAndrew Jeffery if (!ctx) { 202c8df31c1SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 203c8df31c1SAndrew Jeffery } 204c8df31c1SAndrew Jeffery 205c8df31c1SAndrew Jeffery ctx->mode = PLDM_MSGBUF_PLDM_CC; 206c8df31c1SAndrew Jeffery return pldm__msgbuf_init(ctx, minsize, buf, len); 207c8df31c1SAndrew Jeffery } 208c8df31c1SAndrew Jeffery 209c8df31c1SAndrew Jeffery /** 210c8df31c1SAndrew Jeffery * @brief Initialise a msgbuf instance to return errors as negative errno values 211c8df31c1SAndrew Jeffery * 212c8df31c1SAndrew Jeffery * @see pldm__msgbuf_init 213c8df31c1SAndrew Jeffery * 214c8df31c1SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 215c8df31c1SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 216c8df31c1SAndrew Jeffery * @param[in] buf - buffer to be extracted 217c8df31c1SAndrew Jeffery * @param[in] len - size of buffer 218c8df31c1SAndrew Jeffery * 219c8df31c1SAndrew Jeffery * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if 220c8df31c1SAndrew Jeffery * pointer parameters are invalid, or -EOVERFLOW if length constraints 221c8df31c1SAndrew Jeffery * are violated. 222c8df31c1SAndrew Jeffery */ 223c8df31c1SAndrew Jeffery __attribute__((always_inline)) static inline int 224c8df31c1SAndrew Jeffery pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 225c8df31c1SAndrew Jeffery size_t len) 226c8df31c1SAndrew Jeffery { 227c8df31c1SAndrew Jeffery if (!ctx) { 228c8df31c1SAndrew Jeffery return -EINVAL; 229c8df31c1SAndrew Jeffery } 230c8df31c1SAndrew Jeffery 231c8df31c1SAndrew Jeffery ctx->mode = PLDM_MSGBUF_C_ERRNO; 232c8df31c1SAndrew Jeffery return pldm__msgbuf_init(ctx, minsize, buf, len); 233c63f63a2SAndrew Jeffery } 234c63f63a2SAndrew Jeffery 235c63f63a2SAndrew Jeffery /** 236c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 237c63f63a2SAndrew Jeffery * 238c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 239c63f63a2SAndrew Jeffery * 240c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 241c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 242c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 243c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 244c63f63a2SAndrew Jeffery * pointer. 245c63f63a2SAndrew Jeffery */ 24676712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 24776712f69SAndrew Jeffery pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 248c63f63a2SAndrew Jeffery { 249c8df31c1SAndrew Jeffery assert(ctx); 250c8df31c1SAndrew Jeffery if (ctx->remaining < 0) { 251c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 252c63f63a2SAndrew Jeffery } 253c63f63a2SAndrew Jeffery 254c8df31c1SAndrew Jeffery return 0; 255c63f63a2SAndrew Jeffery } 256c63f63a2SAndrew Jeffery 257c63f63a2SAndrew Jeffery /** 258db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 259db7b8324SAndrew Jeffery * 260db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 261db7b8324SAndrew Jeffery * 262db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 263db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 264db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 265db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 266db7b8324SAndrew Jeffery * pointer. 267db7b8324SAndrew Jeffery */ 26876712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 26976712f69SAndrew Jeffery pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 270db7b8324SAndrew Jeffery { 271c8df31c1SAndrew Jeffery assert(ctx); 272c8df31c1SAndrew Jeffery if (ctx->remaining != 0) { 273c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EBADMSG); 274db7b8324SAndrew Jeffery } 275db7b8324SAndrew Jeffery 276c8df31c1SAndrew Jeffery return 0; 277db7b8324SAndrew Jeffery } 278db7b8324SAndrew Jeffery 279db7b8324SAndrew Jeffery /** 280c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 281c63f63a2SAndrew Jeffery * 282c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 283c63f63a2SAndrew Jeffery * 284c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 285c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 286c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 287c63f63a2SAndrew Jeffery * bounds of the buffer. 288c63f63a2SAndrew Jeffery */ 28976712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 29076712f69SAndrew Jeffery pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 291c63f63a2SAndrew Jeffery { 292c63f63a2SAndrew Jeffery int valid; 293c63f63a2SAndrew Jeffery 294c8df31c1SAndrew Jeffery assert(ctx); 295c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 296c63f63a2SAndrew Jeffery 297c63f63a2SAndrew Jeffery ctx->cursor = NULL; 298c63f63a2SAndrew Jeffery ctx->remaining = 0; 299c63f63a2SAndrew Jeffery 300c63f63a2SAndrew Jeffery return valid; 301c63f63a2SAndrew Jeffery } 302c63f63a2SAndrew Jeffery 303c63f63a2SAndrew Jeffery /** 304db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 305db7b8324SAndrew Jeffery * has been completely consumed without overflow 306db7b8324SAndrew Jeffery * 307db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 308db7b8324SAndrew Jeffery * 309db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 310db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 311db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 312db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 313db7b8324SAndrew Jeffery */ 31476712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 31576712f69SAndrew Jeffery pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 316db7b8324SAndrew Jeffery { 317db7b8324SAndrew Jeffery int consumed; 318db7b8324SAndrew Jeffery 319c8df31c1SAndrew Jeffery assert(ctx); 320db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 321db7b8324SAndrew Jeffery 322db7b8324SAndrew Jeffery ctx->cursor = NULL; 323db7b8324SAndrew Jeffery ctx->remaining = 0; 324db7b8324SAndrew Jeffery 325db7b8324SAndrew Jeffery return consumed; 326db7b8324SAndrew Jeffery } 327db7b8324SAndrew Jeffery 32866c7723aSAndrew Jeffery /* 32966c7723aSAndrew Jeffery * Exploit the pre-processor to perform type checking by macro substitution. 33066c7723aSAndrew Jeffery * 33166c7723aSAndrew Jeffery * A C type is defined by its alignment as well as its object 33266c7723aSAndrew Jeffery * size, and compilers have a hammer to enforce it in the form of 33366c7723aSAndrew Jeffery * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in 33466c7723aSAndrew Jeffery * the libpldm public API this presents a problem: Naively attempting to use the 33566c7723aSAndrew Jeffery * msgbuf APIs on a member of a packed struct would yield an error. 33666c7723aSAndrew Jeffery * 33766c7723aSAndrew Jeffery * The msgbuf APIs are implemented such that data is moved through unaligned 33866c7723aSAndrew Jeffery * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must 33966c7723aSAndrew Jeffery * make the object pointers take a trip through `void *` at its API boundary. 34066c7723aSAndrew Jeffery * That presents a bit too much of an opportunity to non-surgically remove your 34166c7723aSAndrew Jeffery * own foot, so here we set about doing something to mitigate that as well. 34266c7723aSAndrew Jeffery * 34366c7723aSAndrew Jeffery * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness 34466c7723aSAndrew Jeffery * only for the purpose of object sizes, disregarding alignment. We have a few 34566c7723aSAndrew Jeffery * constraints that cause some headaches: 34666c7723aSAndrew Jeffery * 34766c7723aSAndrew Jeffery * 1. We have to perform the type-check before a call through a C function, 34866c7723aSAndrew Jeffery * as the function must take the object pointer argument as `void *`. 34966c7723aSAndrew Jeffery * Essentially, this constrains us to doing something with macros. 35066c7723aSAndrew Jeffery * 35166c7723aSAndrew Jeffery * 2. While libpldm is a C library, its test suite is written in C++ to take 35266c7723aSAndrew Jeffery * advantage of gtest. 35366c7723aSAndrew Jeffery * 35466c7723aSAndrew Jeffery * 3. Ideally we'd do something with C's `static_assert()`, however 35566c7723aSAndrew Jeffery * `static_assert()` is defined as void, and as we're constrained to macros, 35666c7723aSAndrew Jeffery * using `static_assert()` would require a statement-expression 35766c7723aSAndrew Jeffery * 35866c7723aSAndrew Jeffery * 4. Currently the project is built with `-std=c17`. CPP statement-expressions 35966c7723aSAndrew Jeffery * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for 36066c7723aSAndrew Jeffery * the purpose of enabling statement-expressions in this one instance. 36166c7723aSAndrew Jeffery * 36266c7723aSAndrew Jeffery * 5. We can achieve a conditional build error using `pldm_require_obj_type()`, 36366c7723aSAndrew Jeffery * however it's implemented in terms of `_Generic()`, which is not available 36466c7723aSAndrew Jeffery * in C++. 36566c7723aSAndrew Jeffery * 36666c7723aSAndrew Jeffery * Combined this means we need separate solutions for C and C++. 36766c7723aSAndrew Jeffery * 36866c7723aSAndrew Jeffery * For C, as we don't have statement-expressions, we need to exploit some other 36966c7723aSAndrew Jeffery * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf 37066c7723aSAndrew Jeffery * API function call. We also have to take care of the fact that the call-sites 37166c7723aSAndrew Jeffery * may be in the context of a variable assignment for error-handling purposes. 37266c7723aSAndrew Jeffery * The key observation is that we can use the comma operator as a sequence point 37366c7723aSAndrew Jeffery * to order the type check before the API call, discarding the "result" value of 37466c7723aSAndrew Jeffery * the type check and yielding the return value of the API call. 37566c7723aSAndrew Jeffery * 37666c7723aSAndrew Jeffery * C++ could be less of a headache than the C as we can leverage template 37766c7723aSAndrew Jeffery * functions. An advantage of template functions is that while their definition 37866c7723aSAndrew Jeffery * is driven by instantion, the definition does not appear at the source 37966c7723aSAndrew Jeffery * location of the instantation, which gives it a great leg-up over the problems 38066c7723aSAndrew Jeffery * we have in the C path. However, the use of the msgbuf APIs in the test suite 38166c7723aSAndrew Jeffery * still makes things somewhat tricky, as the call-sites in the test suite are 38266c7723aSAndrew Jeffery * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that 38366c7723aSAndrew Jeffery * takes both the object type and the required type as template arguments, and 38466c7723aSAndrew Jeffery * then define the object pointer parameter as `void *` for a call through to 38566c7723aSAndrew Jeffery * the appropriate msgbuf API. However, because the msgbuf API call-sites are 38666c7723aSAndrew Jeffery * encapsulated in gtest macros, use of commas in the template specification 38766c7723aSAndrew Jeffery * causes pre-processor confusion. In this way we're constrained to only one 38866c7723aSAndrew Jeffery * template argument per function. 38966c7723aSAndrew Jeffery * 39066c7723aSAndrew Jeffery * Implement the C++ path using template functions that take the destination 39166c7723aSAndrew Jeffery * object type as a template argument, while the name of the function symbols 39266c7723aSAndrew Jeffery * are derived from the required type. The manual implementations of these 39366c7723aSAndrew Jeffery * appear at the end of the header. The type safety is actually enforced 39466c7723aSAndrew Jeffery * by `static_assert()` this time, as we can use statements as we're not 39566c7723aSAndrew Jeffery * constrained to an expression in the templated function body. 39666c7723aSAndrew Jeffery * 39766c7723aSAndrew Jeffery * The invocations of pldm_msgbuf_extract_typecheck() typically result in 39866c7723aSAndrew Jeffery * double-evaluation of some arguments. We're not yet bothered by this for two 39966c7723aSAndrew Jeffery * reasons: 40066c7723aSAndrew Jeffery * 40166c7723aSAndrew Jeffery * 1. The nature of the current call-sites are such that there are no 40266c7723aSAndrew Jeffery * argument expressions that result in undesirable side-effects 40366c7723aSAndrew Jeffery * 40466c7723aSAndrew Jeffery * 2. It's an API internal to the libpldm implementation, and we can fix things 40566c7723aSAndrew Jeffery * whenever something crops up the violates the observation in 1. 40666c7723aSAndrew Jeffery */ 40766c7723aSAndrew Jeffery #ifdef __cplusplus 40866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 40966c7723aSAndrew Jeffery pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__) 41066c7723aSAndrew Jeffery #else 41166c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \ 41266c7723aSAndrew Jeffery (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__)) 41366c7723aSAndrew Jeffery #endif 41466c7723aSAndrew Jeffery 415db7b8324SAndrew Jeffery /** 416c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 417c63f63a2SAndrew Jeffery * 418c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 419c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 420c63f63a2SAndrew Jeffery * 421c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 422c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 423c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 424c63f63a2SAndrew Jeffery */ 42566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst) \ 42666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \ 42766c7723aSAndrew Jeffery dst, ctx, dst) 42876712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 42966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 43076712f69SAndrew Jeffery pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst) 431c63f63a2SAndrew Jeffery { 432c8df31c1SAndrew Jeffery assert(ctx); 433c8df31c1SAndrew Jeffery 434c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 435c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 436c63f63a2SAndrew Jeffery } 437c63f63a2SAndrew Jeffery 4382ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 4392ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 440c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 4412ff8cf89SAndrew Jeffery } 44266c7723aSAndrew Jeffery ctx->remaining -= sizeof(uint8_t); 443c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 444c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 445c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 446c63f63a2SAndrew Jeffery } 447c63f63a2SAndrew Jeffery 44866c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(uint8_t)); 44966c7723aSAndrew Jeffery 450c63f63a2SAndrew Jeffery ctx->cursor++; 451c8df31c1SAndrew Jeffery return 0; 452c63f63a2SAndrew Jeffery } 453c63f63a2SAndrew Jeffery 45466c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst) \ 45566c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \ 45666c7723aSAndrew Jeffery ctx, dst) 45776712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 45866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 45976712f69SAndrew Jeffery pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst) 460c63f63a2SAndrew Jeffery { 461c8df31c1SAndrew Jeffery assert(ctx); 462c8df31c1SAndrew Jeffery 463c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 464c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 465c63f63a2SAndrew Jeffery } 466c63f63a2SAndrew Jeffery 4672ff8cf89SAndrew Jeffery if (ctx->remaining == INTMAX_MIN) { 4682ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 469c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 4702ff8cf89SAndrew Jeffery } 47166c7723aSAndrew Jeffery ctx->remaining -= sizeof(int8_t); 472c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 473c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 474c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 475c63f63a2SAndrew Jeffery } 476c63f63a2SAndrew Jeffery 47766c7723aSAndrew Jeffery memcpy(dst, ctx->cursor, sizeof(int8_t)); 478c63f63a2SAndrew Jeffery ctx->cursor++; 479c8df31c1SAndrew Jeffery return 0; 480c63f63a2SAndrew Jeffery } 481c63f63a2SAndrew Jeffery 48266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst) \ 48366c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \ 48466c7723aSAndrew Jeffery dst, ctx, dst) 48576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 48666c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 48776712f69SAndrew Jeffery pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst) 488c63f63a2SAndrew Jeffery { 489c63f63a2SAndrew Jeffery uint16_t ldst; 490c63f63a2SAndrew Jeffery 491c8df31c1SAndrew Jeffery assert(ctx); 492c8df31c1SAndrew Jeffery 493c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 494c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 495c63f63a2SAndrew Jeffery } 496c63f63a2SAndrew Jeffery 4972ff8cf89SAndrew Jeffery // Check for underflow while tracking the magnitude of the buffer overflow 4982ff8cf89SAndrew Jeffery static_assert( 4992ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5002ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5012ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5022ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5032ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 504c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 5052ff8cf89SAndrew Jeffery } 5062ff8cf89SAndrew Jeffery 507c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 508c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 509c63f63a2SAndrew Jeffery // we've overflowed. 510c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 511c63f63a2SAndrew Jeffery 512c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 513c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 514c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 515c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 516c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 517c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 518c63f63a2SAndrew Jeffery } 519c63f63a2SAndrew Jeffery 520c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 521c63f63a2SAndrew Jeffery // issues on the target architecture 522c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 523c63f63a2SAndrew Jeffery 524c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 52566c7723aSAndrew Jeffery ldst = le16toh(ldst); 52666c7723aSAndrew Jeffery 52766c7723aSAndrew Jeffery // Allow storing to unaligned 52866c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 52966c7723aSAndrew Jeffery 530c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 531c63f63a2SAndrew Jeffery 532c8df31c1SAndrew Jeffery return 0; 533c63f63a2SAndrew Jeffery } 534c63f63a2SAndrew Jeffery 53566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst) \ 53666c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \ 53766c7723aSAndrew Jeffery dst, ctx, dst) 53876712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 53966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 54076712f69SAndrew Jeffery pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst) 541c63f63a2SAndrew Jeffery { 542c63f63a2SAndrew Jeffery int16_t ldst; 543c63f63a2SAndrew Jeffery 544c8df31c1SAndrew Jeffery assert(ctx); 545c8df31c1SAndrew Jeffery 546c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 547c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 548c63f63a2SAndrew Jeffery } 549c63f63a2SAndrew Jeffery 5502ff8cf89SAndrew Jeffery static_assert( 5512ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5522ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5532ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5542ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5552ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 556c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 5572ff8cf89SAndrew Jeffery } 558c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 559c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 560c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 561c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 562c63f63a2SAndrew Jeffery } 563c63f63a2SAndrew Jeffery 564c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 565c63f63a2SAndrew Jeffery 56666c7723aSAndrew Jeffery ldst = le16toh(ldst); 56766c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 568c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 569c63f63a2SAndrew Jeffery 570c8df31c1SAndrew Jeffery return 0; 571c63f63a2SAndrew Jeffery } 572c63f63a2SAndrew Jeffery 57366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst) \ 57466c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \ 57566c7723aSAndrew Jeffery dst, ctx, dst) 57676712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 57766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 57876712f69SAndrew Jeffery pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst) 579c63f63a2SAndrew Jeffery { 580c63f63a2SAndrew Jeffery uint32_t ldst; 581c63f63a2SAndrew Jeffery 582c8df31c1SAndrew Jeffery assert(ctx); 583c8df31c1SAndrew Jeffery 584c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 585c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 586c63f63a2SAndrew Jeffery } 587c63f63a2SAndrew Jeffery 5882ff8cf89SAndrew Jeffery static_assert( 5892ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 5902ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 5912ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 5922ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 5932ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 594c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 5952ff8cf89SAndrew Jeffery } 596c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 597c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 598c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 599c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 600c63f63a2SAndrew Jeffery } 601c63f63a2SAndrew Jeffery 602c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 60366c7723aSAndrew Jeffery ldst = le32toh(ldst); 60466c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 605c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 606c63f63a2SAndrew Jeffery 607c8df31c1SAndrew Jeffery return 0; 608c63f63a2SAndrew Jeffery } 609c63f63a2SAndrew Jeffery 61066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst) \ 61166c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \ 61266c7723aSAndrew Jeffery dst, ctx, dst) 61376712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 61466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 61576712f69SAndrew Jeffery pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst) 616c63f63a2SAndrew Jeffery { 617c63f63a2SAndrew Jeffery int32_t ldst; 618c63f63a2SAndrew Jeffery 619c8df31c1SAndrew Jeffery assert(ctx); 620c8df31c1SAndrew Jeffery 621c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 622c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 623c63f63a2SAndrew Jeffery } 624c63f63a2SAndrew Jeffery 6252ff8cf89SAndrew Jeffery static_assert( 6262ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6272ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 6282ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6292ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 6302ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 631c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 6322ff8cf89SAndrew Jeffery } 633c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 634c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 635c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 636c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 637c63f63a2SAndrew Jeffery } 638c63f63a2SAndrew Jeffery 639c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 64066c7723aSAndrew Jeffery ldst = le32toh(ldst); 64166c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 642c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 643c63f63a2SAndrew Jeffery 644c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 645c63f63a2SAndrew Jeffery } 646c63f63a2SAndrew Jeffery 64766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst) \ 64866c7723aSAndrew Jeffery pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \ 64966c7723aSAndrew Jeffery dst, ctx, dst) 65076712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 65166c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 65276712f69SAndrew Jeffery pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst) 653c63f63a2SAndrew Jeffery { 654c63f63a2SAndrew Jeffery uint32_t ldst; 655c63f63a2SAndrew Jeffery 656c8df31c1SAndrew Jeffery static_assert(sizeof(real32_t) == sizeof(ldst), 65766c7723aSAndrew Jeffery "Mismatched type sizes for dst and ldst"); 65866c7723aSAndrew Jeffery 659c8df31c1SAndrew Jeffery assert(ctx); 660c8df31c1SAndrew Jeffery 661c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 662c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 663c63f63a2SAndrew Jeffery } 664c63f63a2SAndrew Jeffery 6652ff8cf89SAndrew Jeffery static_assert( 6662ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 6672ff8cf89SAndrew Jeffery sizeof(ldst) < INTMAX_MAX, 6682ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 6692ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) { 6702ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 671c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 6722ff8cf89SAndrew Jeffery } 673c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 674c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 675c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 676c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 677c63f63a2SAndrew Jeffery } 678c63f63a2SAndrew Jeffery 679c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 680c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 68166c7723aSAndrew Jeffery memcpy(dst, &ldst, sizeof(ldst)); 68266c7723aSAndrew Jeffery ctx->cursor += sizeof(ldst); 683c63f63a2SAndrew Jeffery 684c8df31c1SAndrew Jeffery return 0; 685c63f63a2SAndrew Jeffery } 686c63f63a2SAndrew Jeffery 68766c7723aSAndrew Jeffery /** 68866c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the lvalue named by dst. 68966c7723aSAndrew Jeffery * 69066c7723aSAndrew Jeffery * @param ctx The msgbuf context object 69166c7723aSAndrew Jeffery * @param dst The lvalue into which the field at the msgbuf cursor should be 69266c7723aSAndrew Jeffery * extracted 69366c7723aSAndrew Jeffery * 69466c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 69566c7723aSAndrew Jeffery */ 696c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 69766c7723aSAndrew Jeffery _Generic((dst), \ 69866c7723aSAndrew Jeffery uint8_t: pldm__msgbuf_extract_uint8, \ 69966c7723aSAndrew Jeffery int8_t: pldm__msgbuf_extract_int8, \ 70066c7723aSAndrew Jeffery uint16_t: pldm__msgbuf_extract_uint16, \ 70166c7723aSAndrew Jeffery int16_t: pldm__msgbuf_extract_int16, \ 70266c7723aSAndrew Jeffery uint32_t: pldm__msgbuf_extract_uint32, \ 70366c7723aSAndrew Jeffery int32_t: pldm__msgbuf_extract_int32, \ 70466c7723aSAndrew Jeffery real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst)) 70566c7723aSAndrew Jeffery 70666c7723aSAndrew Jeffery /** 70766c7723aSAndrew Jeffery * Extract the field at the msgbuf cursor into the object pointed-to by dst. 70866c7723aSAndrew Jeffery * 70966c7723aSAndrew Jeffery * @param ctx The msgbuf context object 71066c7723aSAndrew Jeffery * @param dst The pointer to the object into which the field at the msgbuf 71166c7723aSAndrew Jeffery * cursor should be extracted 71266c7723aSAndrew Jeffery * 71366c7723aSAndrew Jeffery * @return PLDM_SUCCESS on success, otherwise another value on error 71466c7723aSAndrew Jeffery */ 71566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst) \ 71666c7723aSAndrew Jeffery _Generic((dst), \ 71766c7723aSAndrew Jeffery uint8_t *: pldm__msgbuf_extract_uint8, \ 71866c7723aSAndrew Jeffery int8_t *: pldm__msgbuf_extract_int8, \ 71966c7723aSAndrew Jeffery uint16_t *: pldm__msgbuf_extract_uint16, \ 72066c7723aSAndrew Jeffery int16_t *: pldm__msgbuf_extract_int16, \ 72166c7723aSAndrew Jeffery uint32_t *: pldm__msgbuf_extract_uint32, \ 72266c7723aSAndrew Jeffery int32_t *: pldm__msgbuf_extract_int32, \ 72366c7723aSAndrew Jeffery real32_t *: pldm__msgbuf_extract_real32)(ctx, dst) 724c63f63a2SAndrew Jeffery 72576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 72676712f69SAndrew Jeffery pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst, 72776712f69SAndrew Jeffery size_t count) 728369b121aSAndrew Jeffery { 729c8df31c1SAndrew Jeffery assert(ctx); 730c8df31c1SAndrew Jeffery 731c8df31c1SAndrew Jeffery if (!ctx->cursor || !dst) { 732c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 733369b121aSAndrew Jeffery } 734369b121aSAndrew Jeffery 735369b121aSAndrew Jeffery if (!count) { 736c8df31c1SAndrew Jeffery return 0; 737369b121aSAndrew Jeffery } 738369b121aSAndrew Jeffery 7392ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 7402ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 741c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 742369b121aSAndrew Jeffery } 7432ff8cf89SAndrew Jeffery #endif 744369b121aSAndrew Jeffery 7452ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 746c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 7472ff8cf89SAndrew Jeffery } 7482ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 749369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 750369b121aSAndrew Jeffery if (ctx->remaining < 0) { 751c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 752369b121aSAndrew Jeffery } 753369b121aSAndrew Jeffery 754a065eccbSAndrew Jeffery memcpy(dst, ctx->cursor, count); 755a065eccbSAndrew Jeffery ctx->cursor += count; 756369b121aSAndrew Jeffery 757c8df31c1SAndrew Jeffery return 0; 758369b121aSAndrew Jeffery } 759369b121aSAndrew Jeffery 760369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 76137dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 76237dd6a3dSAndrew Jeffery count) 763369b121aSAndrew Jeffery 76476712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 76576712f69SAndrew Jeffery pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src) 766062c8762SThu Nguyen { 767062c8762SThu Nguyen uint32_t val = htole32(src); 768062c8762SThu Nguyen 769c8df31c1SAndrew Jeffery assert(ctx); 770c8df31c1SAndrew Jeffery 771c8df31c1SAndrew Jeffery if (!ctx->cursor) { 772c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 773062c8762SThu Nguyen } 774062c8762SThu Nguyen 7752ff8cf89SAndrew Jeffery static_assert( 7762ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 7772ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 7782ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 7792ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 7802ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 781c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 7822ff8cf89SAndrew Jeffery } 783062c8762SThu Nguyen ctx->remaining -= sizeof(src); 784062c8762SThu Nguyen assert(ctx->remaining >= 0); 785062c8762SThu Nguyen if (ctx->remaining < 0) { 786c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 787062c8762SThu Nguyen } 788062c8762SThu Nguyen 789062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 790062c8762SThu Nguyen ctx->cursor += sizeof(src); 791062c8762SThu Nguyen 792c8df31c1SAndrew Jeffery return 0; 793062c8762SThu Nguyen } 794062c8762SThu Nguyen 79576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 79676712f69SAndrew Jeffery pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src) 797062c8762SThu Nguyen { 798062c8762SThu Nguyen uint16_t val = htole16(src); 799062c8762SThu Nguyen 800c8df31c1SAndrew Jeffery assert(ctx); 801c8df31c1SAndrew Jeffery 802c8df31c1SAndrew Jeffery if (!ctx->cursor) { 803c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 804062c8762SThu Nguyen } 805062c8762SThu Nguyen 8062ff8cf89SAndrew Jeffery static_assert( 8072ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8082ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8092ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8102ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8112ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 812c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8132ff8cf89SAndrew Jeffery } 814062c8762SThu Nguyen ctx->remaining -= sizeof(src); 815062c8762SThu Nguyen assert(ctx->remaining >= 0); 816062c8762SThu Nguyen if (ctx->remaining < 0) { 817c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 818062c8762SThu Nguyen } 819062c8762SThu Nguyen 820062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 821062c8762SThu Nguyen ctx->cursor += sizeof(src); 822062c8762SThu Nguyen 823c8df31c1SAndrew Jeffery return 0; 824062c8762SThu Nguyen } 825062c8762SThu Nguyen 82676712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 82776712f69SAndrew Jeffery pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src) 828062c8762SThu Nguyen { 829c8df31c1SAndrew Jeffery assert(ctx); 830c8df31c1SAndrew Jeffery 831c8df31c1SAndrew Jeffery if (!ctx->cursor) { 832c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 833062c8762SThu Nguyen } 834062c8762SThu Nguyen 8352ff8cf89SAndrew Jeffery static_assert( 8362ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8372ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8382ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8392ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8402ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 841c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8422ff8cf89SAndrew Jeffery } 843062c8762SThu Nguyen ctx->remaining -= sizeof(src); 844062c8762SThu Nguyen assert(ctx->remaining >= 0); 845062c8762SThu Nguyen if (ctx->remaining < 0) { 846c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 847062c8762SThu Nguyen } 848062c8762SThu Nguyen 849062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 850062c8762SThu Nguyen ctx->cursor += sizeof(src); 851062c8762SThu Nguyen 852c8df31c1SAndrew Jeffery return 0; 853062c8762SThu Nguyen } 854062c8762SThu Nguyen 85576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 85676712f69SAndrew Jeffery pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src) 857062c8762SThu Nguyen { 858062c8762SThu Nguyen int32_t val = htole32(src); 859062c8762SThu Nguyen 860c8df31c1SAndrew Jeffery assert(ctx); 861c8df31c1SAndrew Jeffery 862c8df31c1SAndrew Jeffery if (!ctx->cursor) { 863c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 864062c8762SThu Nguyen } 865062c8762SThu Nguyen 8662ff8cf89SAndrew Jeffery static_assert( 8672ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8682ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 8692ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 8702ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 8712ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 872c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 8732ff8cf89SAndrew Jeffery } 874062c8762SThu Nguyen ctx->remaining -= sizeof(src); 875062c8762SThu Nguyen assert(ctx->remaining >= 0); 876062c8762SThu Nguyen if (ctx->remaining < 0) { 877c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 878062c8762SThu Nguyen } 879062c8762SThu Nguyen 880062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 881062c8762SThu Nguyen ctx->cursor += sizeof(src); 882062c8762SThu Nguyen 883c8df31c1SAndrew Jeffery return 0; 884062c8762SThu Nguyen } 885062c8762SThu Nguyen 88676712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 88776712f69SAndrew Jeffery pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src) 888062c8762SThu Nguyen { 889062c8762SThu Nguyen int16_t val = htole16(src); 890062c8762SThu Nguyen 891c8df31c1SAndrew Jeffery assert(ctx); 892c8df31c1SAndrew Jeffery 893c8df31c1SAndrew Jeffery if (!ctx->cursor) { 894c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 895062c8762SThu Nguyen } 896062c8762SThu Nguyen 8972ff8cf89SAndrew Jeffery static_assert( 8982ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 8992ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 9002ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 9012ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 9022ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 903c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9042ff8cf89SAndrew Jeffery } 905062c8762SThu Nguyen ctx->remaining -= sizeof(src); 906062c8762SThu Nguyen assert(ctx->remaining >= 0); 907062c8762SThu Nguyen if (ctx->remaining < 0) { 908c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 909062c8762SThu Nguyen } 910062c8762SThu Nguyen 911062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 912062c8762SThu Nguyen ctx->cursor += sizeof(src); 913062c8762SThu Nguyen 914c8df31c1SAndrew Jeffery return 0; 915062c8762SThu Nguyen } 916062c8762SThu Nguyen 91776712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 91876712f69SAndrew Jeffery pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src) 919062c8762SThu Nguyen { 920c8df31c1SAndrew Jeffery assert(ctx); 921c8df31c1SAndrew Jeffery 922c8df31c1SAndrew Jeffery if (!ctx->cursor) { 923c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 924062c8762SThu Nguyen } 925062c8762SThu Nguyen 9262ff8cf89SAndrew Jeffery static_assert( 9272ff8cf89SAndrew Jeffery // NOLINTNEXTLINE(bugprone-sizeof-expression) 9282ff8cf89SAndrew Jeffery sizeof(src) < INTMAX_MAX, 9292ff8cf89SAndrew Jeffery "The following addition may not uphold the runtime assertion"); 9302ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) { 9312ff8cf89SAndrew Jeffery assert(ctx->remaining < 0); 932c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9332ff8cf89SAndrew Jeffery } 934062c8762SThu Nguyen ctx->remaining -= sizeof(src); 935062c8762SThu Nguyen assert(ctx->remaining >= 0); 936062c8762SThu Nguyen if (ctx->remaining < 0) { 937c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 938062c8762SThu Nguyen } 939062c8762SThu Nguyen 940062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 941062c8762SThu Nguyen ctx->cursor += sizeof(src); 942062c8762SThu Nguyen 943c8df31c1SAndrew Jeffery return 0; 944062c8762SThu Nguyen } 945062c8762SThu Nguyen 946062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 94737dd6a3dSAndrew Jeffery _Generic((src), \ 94837dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 94937dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 95037dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 95137dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 95237dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 95337dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 954062c8762SThu Nguyen 95576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 95676712f69SAndrew Jeffery pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src, 957062c8762SThu Nguyen size_t count) 958062c8762SThu Nguyen { 959c8df31c1SAndrew Jeffery assert(ctx); 960c8df31c1SAndrew Jeffery 961c8df31c1SAndrew Jeffery if (!ctx->cursor || !src) { 962c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 963062c8762SThu Nguyen } 964062c8762SThu Nguyen 965062c8762SThu Nguyen if (!count) { 966c8df31c1SAndrew Jeffery return 0; 967062c8762SThu Nguyen } 968062c8762SThu Nguyen 9692ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 9702ff8cf89SAndrew Jeffery if (count > INTMAX_MAX) { 971c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 972062c8762SThu Nguyen } 9732ff8cf89SAndrew Jeffery #endif 974062c8762SThu Nguyen 9752ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)count) { 976c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 9772ff8cf89SAndrew Jeffery } 9782ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)count; 979062c8762SThu Nguyen assert(ctx->remaining >= 0); 980062c8762SThu Nguyen if (ctx->remaining < 0) { 981c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 982062c8762SThu Nguyen } 983062c8762SThu Nguyen 984a065eccbSAndrew Jeffery memcpy(ctx->cursor, src, count); 985a065eccbSAndrew Jeffery ctx->cursor += count; 986062c8762SThu Nguyen 987c8df31c1SAndrew Jeffery return 0; 988062c8762SThu Nguyen } 989062c8762SThu Nguyen 990062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 99137dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 99237dd6a3dSAndrew Jeffery count) 993062c8762SThu Nguyen 99476712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 99576712f69SAndrew Jeffery pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required, 99676712f69SAndrew Jeffery void **cursor) 997062c8762SThu Nguyen { 998c8df31c1SAndrew Jeffery assert(ctx); 999c8df31c1SAndrew Jeffery 1000c8df31c1SAndrew Jeffery if (!ctx->cursor || !cursor || *cursor) { 1001c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 1002062c8762SThu Nguyen } 1003062c8762SThu Nguyen 10042ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX 10052ff8cf89SAndrew Jeffery if (required > INTMAX_MAX) { 1006c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1007062c8762SThu Nguyen } 10082ff8cf89SAndrew Jeffery #endif 1009062c8762SThu Nguyen 10102ff8cf89SAndrew Jeffery if (ctx->remaining < INTMAX_MIN + (intmax_t)required) { 1011c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 10122ff8cf89SAndrew Jeffery } 10132ff8cf89SAndrew Jeffery ctx->remaining -= (intmax_t)required; 1014062c8762SThu Nguyen assert(ctx->remaining >= 0); 1015062c8762SThu Nguyen if (ctx->remaining < 0) { 1016c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1017062c8762SThu Nguyen } 1018062c8762SThu Nguyen 1019062c8762SThu Nguyen *cursor = ctx->cursor; 1020062c8762SThu Nguyen ctx->cursor += required; 1021062c8762SThu Nguyen 1022c8df31c1SAndrew Jeffery return 0; 1023062c8762SThu Nguyen } 1024062c8762SThu Nguyen 102576712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 102676712f69SAndrew Jeffery pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len) 1027062c8762SThu Nguyen { 1028c8df31c1SAndrew Jeffery assert(ctx); 1029c8df31c1SAndrew Jeffery 1030c8df31c1SAndrew Jeffery if (!ctx->cursor || !cursor || *cursor || !len) { 1031c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EINVAL); 1032062c8762SThu Nguyen } 1033062c8762SThu Nguyen 1034062c8762SThu Nguyen assert(ctx->remaining >= 0); 1035062c8762SThu Nguyen if (ctx->remaining < 0) { 1036c8df31c1SAndrew Jeffery return pldm_msgbuf_status(ctx, EOVERFLOW); 1037062c8762SThu Nguyen } 1038062c8762SThu Nguyen 1039062c8762SThu Nguyen *cursor = ctx->cursor; 1040062c8762SThu Nguyen ctx->cursor += ctx->remaining; 1041062c8762SThu Nguyen *len = ctx->remaining; 1042062c8762SThu Nguyen ctx->remaining = 0; 1043062c8762SThu Nguyen 1044c8df31c1SAndrew Jeffery return 0; 1045062c8762SThu Nguyen } 1046909bf7c2SVarsha Kaverappa 1047909bf7c2SVarsha Kaverappa /** 1048909bf7c2SVarsha Kaverappa * @brief pldm_msgbuf copy data between two msg buffers 1049909bf7c2SVarsha Kaverappa * 1050909bf7c2SVarsha Kaverappa * @param[inout] src - pldm_msgbuf for source from where value should be copied 1051909bf7c2SVarsha Kaverappa * @param[inout] dst - destination of copy from source 1052909bf7c2SVarsha Kaverappa * @param[in] size - size of data to be copied 1053909bf7c2SVarsha Kaverappa * @param[in] description - description of data copied 1054909bf7c2SVarsha Kaverappa * 1055909bf7c2SVarsha Kaverappa * @return PLDM_SUCCESS if buffer accesses were in-bounds, 1056909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_LENGTH otherwise. 1057909bf7c2SVarsha Kaverappa * PLDM_ERROR_INVALID_DATA if input is invalid 1058909bf7c2SVarsha Kaverappa */ 1059909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name) \ 1060909bf7c2SVarsha Kaverappa pldm__msgbuf_copy(dst, src, sizeof(type), #name) 106176712f69SAndrew Jeffery __attribute__((always_inline)) static inline int 1062909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 106376712f69SAndrew Jeffery pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size, 1064909bf7c2SVarsha Kaverappa const char *description) 1065909bf7c2SVarsha Kaverappa { 1066c8df31c1SAndrew Jeffery assert(src); 1067c8df31c1SAndrew Jeffery assert(dst); 1068c8df31c1SAndrew Jeffery assert(src->mode == dst->mode); 1069c8df31c1SAndrew Jeffery 1070c8df31c1SAndrew Jeffery if (!src->cursor || !dst->cursor || !description) { 1071c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EINVAL); 1072909bf7c2SVarsha Kaverappa } 1073909bf7c2SVarsha Kaverappa 1074909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX 1075909bf7c2SVarsha Kaverappa if (size > INTMAX_MAX) { 1076c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1077909bf7c2SVarsha Kaverappa } 1078909bf7c2SVarsha Kaverappa #endif 1079909bf7c2SVarsha Kaverappa 1080909bf7c2SVarsha Kaverappa if (src->remaining < INTMAX_MIN + (intmax_t)size) { 1081c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1082909bf7c2SVarsha Kaverappa } 1083909bf7c2SVarsha Kaverappa 1084909bf7c2SVarsha Kaverappa if (dst->remaining < INTMAX_MIN + (intmax_t)size) { 1085c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1086909bf7c2SVarsha Kaverappa } 1087909bf7c2SVarsha Kaverappa 1088909bf7c2SVarsha Kaverappa src->remaining -= (intmax_t)size; 1089909bf7c2SVarsha Kaverappa assert(src->remaining >= 0); 1090909bf7c2SVarsha Kaverappa if (src->remaining < 0) { 1091c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1092909bf7c2SVarsha Kaverappa } 1093909bf7c2SVarsha Kaverappa 1094909bf7c2SVarsha Kaverappa dst->remaining -= (intmax_t)size; 1095909bf7c2SVarsha Kaverappa assert(dst->remaining >= 0); 1096909bf7c2SVarsha Kaverappa if (dst->remaining < 0) { 1097c8df31c1SAndrew Jeffery return pldm_msgbuf_status(dst, EOVERFLOW); 1098909bf7c2SVarsha Kaverappa } 1099909bf7c2SVarsha Kaverappa 1100909bf7c2SVarsha Kaverappa memcpy(dst->cursor, src->cursor, size); 1101909bf7c2SVarsha Kaverappa src->cursor += size; 1102909bf7c2SVarsha Kaverappa dst->cursor += size; 1103909bf7c2SVarsha Kaverappa 1104c8df31c1SAndrew Jeffery return 0; 1105909bf7c2SVarsha Kaverappa } 1106c8df31c1SAndrew Jeffery 1107c63f63a2SAndrew Jeffery #ifdef __cplusplus 1108c63f63a2SAndrew Jeffery } 1109c63f63a2SAndrew Jeffery #endif 1110c63f63a2SAndrew Jeffery 111166c7723aSAndrew Jeffery #ifdef __cplusplus 111266c7723aSAndrew Jeffery #include <type_traits> 111366c7723aSAndrew Jeffery 111466c7723aSAndrew Jeffery template <typename T> 111566c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx, 111666c7723aSAndrew Jeffery void *buf) 111766c7723aSAndrew Jeffery { 111866c7723aSAndrew Jeffery static_assert(std::is_same<uint8_t *, T>::value); 111966c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint8(ctx, buf); 112066c7723aSAndrew Jeffery } 112166c7723aSAndrew Jeffery 112266c7723aSAndrew Jeffery template <typename T> 112366c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx, 112466c7723aSAndrew Jeffery void *buf) 112566c7723aSAndrew Jeffery { 112666c7723aSAndrew Jeffery static_assert(std::is_same<int8_t *, T>::value); 112766c7723aSAndrew Jeffery return pldm__msgbuf_extract_int8(ctx, buf); 112866c7723aSAndrew Jeffery } 112966c7723aSAndrew Jeffery 113066c7723aSAndrew Jeffery template <typename T> 113166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx, 113266c7723aSAndrew Jeffery void *buf) 113366c7723aSAndrew Jeffery { 113466c7723aSAndrew Jeffery static_assert(std::is_same<uint16_t *, T>::value); 113566c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint16(ctx, buf); 113666c7723aSAndrew Jeffery } 113766c7723aSAndrew Jeffery 113866c7723aSAndrew Jeffery template <typename T> 113966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx, 114066c7723aSAndrew Jeffery void *buf) 114166c7723aSAndrew Jeffery { 114266c7723aSAndrew Jeffery static_assert(std::is_same<int16_t *, T>::value); 114366c7723aSAndrew Jeffery return pldm__msgbuf_extract_int16(ctx, buf); 114466c7723aSAndrew Jeffery } 114566c7723aSAndrew Jeffery 114666c7723aSAndrew Jeffery template <typename T> 114766c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx, 114866c7723aSAndrew Jeffery void *buf) 114966c7723aSAndrew Jeffery { 115066c7723aSAndrew Jeffery static_assert(std::is_same<uint32_t *, T>::value); 115166c7723aSAndrew Jeffery return pldm__msgbuf_extract_uint32(ctx, buf); 115266c7723aSAndrew Jeffery } 115366c7723aSAndrew Jeffery 115466c7723aSAndrew Jeffery template <typename T> 115566c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx, 115666c7723aSAndrew Jeffery void *buf) 115766c7723aSAndrew Jeffery { 115866c7723aSAndrew Jeffery static_assert(std::is_same<int32_t *, T>::value); 115966c7723aSAndrew Jeffery return pldm__msgbuf_extract_int32(ctx, buf); 116066c7723aSAndrew Jeffery } 116166c7723aSAndrew Jeffery 116266c7723aSAndrew Jeffery template <typename T> 116366c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx, 116466c7723aSAndrew Jeffery void *buf) 116566c7723aSAndrew Jeffery { 116666c7723aSAndrew Jeffery static_assert(std::is_same<real32_t *, T>::value); 116766c7723aSAndrew Jeffery return pldm__msgbuf_extract_real32(ctx, buf); 116866c7723aSAndrew Jeffery } 116966c7723aSAndrew Jeffery #endif 117066c7723aSAndrew Jeffery 1171c63f63a2SAndrew Jeffery #endif /* BUF_H */ 1172