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 5c63f63a2SAndrew Jeffery #ifdef __cplusplus 637dd6a3dSAndrew Jeffery /* 737dd6a3dSAndrew Jeffery * Fix up C11's _Static_assert() vs C++'s static_assert(). 837dd6a3dSAndrew Jeffery * 937dd6a3dSAndrew Jeffery * Can we please have nice things for once. 1037dd6a3dSAndrew Jeffery */ 1137dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 1237dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__) 13c63f63a2SAndrew Jeffery extern "C" { 14c63f63a2SAndrew Jeffery #endif 15c63f63a2SAndrew Jeffery 16*b0c1d20aSAndrew Jeffery #include <libpldm/base.h> 17*b0c1d20aSAndrew Jeffery #include <libpldm/pldm_types.h> 18c63f63a2SAndrew Jeffery 19c63f63a2SAndrew Jeffery #include <assert.h> 20c63f63a2SAndrew Jeffery #include <endian.h> 21c63f63a2SAndrew Jeffery #include <limits.h> 22c63f63a2SAndrew Jeffery #include <stdbool.h> 23c63f63a2SAndrew Jeffery #include <string.h> 24c63f63a2SAndrew Jeffery #include <sys/types.h> 25c63f63a2SAndrew Jeffery 26c63f63a2SAndrew Jeffery struct pldm_msgbuf { 27062c8762SThu Nguyen uint8_t *cursor; 28c63f63a2SAndrew Jeffery ssize_t remaining; 29c63f63a2SAndrew Jeffery }; 30c63f63a2SAndrew Jeffery 31c63f63a2SAndrew Jeffery /** 32c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 33c63f63a2SAndrew Jeffery * 34c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 35c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 36c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 37c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 38c63f63a2SAndrew Jeffery * 39c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 40c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 41c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 42c63f63a2SAndrew Jeffery */ 435646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int 445646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 455646f23bSAndrew Jeffery size_t len) 46c63f63a2SAndrew Jeffery { 47c63f63a2SAndrew Jeffery uint8_t *end; 48c63f63a2SAndrew Jeffery 49c63f63a2SAndrew Jeffery if (!ctx || !buf) { 50c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 51c63f63a2SAndrew Jeffery } 52c63f63a2SAndrew Jeffery 53c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 54c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 55c63f63a2SAndrew Jeffery } 56c63f63a2SAndrew Jeffery 57c63f63a2SAndrew Jeffery end = (uint8_t *)buf + len; 58c63f63a2SAndrew Jeffery if (end && end < (uint8_t *)buf) { 59c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 60c63f63a2SAndrew Jeffery } 61c63f63a2SAndrew Jeffery 62c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 63c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 64c63f63a2SAndrew Jeffery 65c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 66c63f63a2SAndrew Jeffery } 67c63f63a2SAndrew Jeffery 68c63f63a2SAndrew Jeffery /** 69c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 70c63f63a2SAndrew Jeffery * 71c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 72c63f63a2SAndrew Jeffery * 73c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 74c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 75c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 76c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 77c63f63a2SAndrew Jeffery * pointer. 78c63f63a2SAndrew Jeffery */ 79c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 80c63f63a2SAndrew Jeffery { 81c63f63a2SAndrew Jeffery if (!ctx) { 82c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 83c63f63a2SAndrew Jeffery } 84c63f63a2SAndrew Jeffery 85c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 86c63f63a2SAndrew Jeffery } 87c63f63a2SAndrew Jeffery 88c63f63a2SAndrew Jeffery /** 89db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 90db7b8324SAndrew Jeffery * 91db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 92db7b8324SAndrew Jeffery * 93db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 94db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 95db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 96db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 97db7b8324SAndrew Jeffery * pointer. 98db7b8324SAndrew Jeffery */ 99db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 100db7b8324SAndrew Jeffery { 101db7b8324SAndrew Jeffery if (!ctx) { 102db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 103db7b8324SAndrew Jeffery } 104db7b8324SAndrew Jeffery 105db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 106db7b8324SAndrew Jeffery } 107db7b8324SAndrew Jeffery 108db7b8324SAndrew Jeffery /** 109c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 110c63f63a2SAndrew Jeffery * 111c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 112c63f63a2SAndrew Jeffery * 113c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 114c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 115c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 116c63f63a2SAndrew Jeffery * bounds of the buffer. 117c63f63a2SAndrew Jeffery */ 118c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 119c63f63a2SAndrew Jeffery { 120c63f63a2SAndrew Jeffery int valid; 121c63f63a2SAndrew Jeffery 122c63f63a2SAndrew Jeffery if (!ctx) { 123c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 124c63f63a2SAndrew Jeffery } 125c63f63a2SAndrew Jeffery 126c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 127c63f63a2SAndrew Jeffery 128c63f63a2SAndrew Jeffery ctx->cursor = NULL; 129c63f63a2SAndrew Jeffery ctx->remaining = 0; 130c63f63a2SAndrew Jeffery 131c63f63a2SAndrew Jeffery return valid; 132c63f63a2SAndrew Jeffery } 133c63f63a2SAndrew Jeffery 134c63f63a2SAndrew Jeffery /** 135db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 136db7b8324SAndrew Jeffery * has been completely consumed without overflow 137db7b8324SAndrew Jeffery * 138db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 139db7b8324SAndrew Jeffery * 140db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 141db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 142db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 143db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 144db7b8324SAndrew Jeffery */ 145db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 146db7b8324SAndrew Jeffery { 147db7b8324SAndrew Jeffery int consumed; 148db7b8324SAndrew Jeffery 149db7b8324SAndrew Jeffery if (!ctx) { 150db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 151db7b8324SAndrew Jeffery } 152db7b8324SAndrew Jeffery 153db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 154db7b8324SAndrew Jeffery 155db7b8324SAndrew Jeffery ctx->cursor = NULL; 156db7b8324SAndrew Jeffery ctx->remaining = 0; 157db7b8324SAndrew Jeffery 158db7b8324SAndrew Jeffery return consumed; 159db7b8324SAndrew Jeffery } 160db7b8324SAndrew Jeffery 161db7b8324SAndrew Jeffery /** 162c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 163c63f63a2SAndrew Jeffery * 164c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 165c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 166c63f63a2SAndrew Jeffery * 167c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 168c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 169c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 170c63f63a2SAndrew Jeffery */ 171c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx, 172c63f63a2SAndrew Jeffery uint8_t *dst) 173c63f63a2SAndrew Jeffery { 174c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 175c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 176c63f63a2SAndrew Jeffery } 177c63f63a2SAndrew Jeffery 178c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 179c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 180c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 181c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 182c63f63a2SAndrew Jeffery } 183c63f63a2SAndrew Jeffery 184c63f63a2SAndrew Jeffery *dst = *((uint8_t *)(ctx->cursor)); 185c63f63a2SAndrew Jeffery ctx->cursor++; 186c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 187c63f63a2SAndrew Jeffery } 188c63f63a2SAndrew Jeffery 189c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst) 190c63f63a2SAndrew Jeffery { 191c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 192c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 193c63f63a2SAndrew Jeffery } 194c63f63a2SAndrew Jeffery 195c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 196c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 197c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 198c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 199c63f63a2SAndrew Jeffery } 200c63f63a2SAndrew Jeffery 201c63f63a2SAndrew Jeffery *dst = *((int8_t *)(ctx->cursor)); 202c63f63a2SAndrew Jeffery ctx->cursor++; 203c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 204c63f63a2SAndrew Jeffery } 205c63f63a2SAndrew Jeffery 206c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 207c63f63a2SAndrew Jeffery uint16_t *dst) 208c63f63a2SAndrew Jeffery { 209c63f63a2SAndrew Jeffery uint16_t ldst; 210c63f63a2SAndrew Jeffery 211c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 212c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 213c63f63a2SAndrew Jeffery } 214c63f63a2SAndrew Jeffery 215c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 216c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 217c63f63a2SAndrew Jeffery // we've overflowed. 218c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 219c63f63a2SAndrew Jeffery 220c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 221c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 222c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 223c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 224c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 225c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 226c63f63a2SAndrew Jeffery } 227c63f63a2SAndrew Jeffery 228c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 229c63f63a2SAndrew Jeffery // issues on the target architecture 230c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 231c63f63a2SAndrew Jeffery 232c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 233c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 234c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 235c63f63a2SAndrew Jeffery 236c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 237c63f63a2SAndrew Jeffery } 238c63f63a2SAndrew Jeffery 239c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx, 240c63f63a2SAndrew Jeffery int16_t *dst) 241c63f63a2SAndrew Jeffery { 242c63f63a2SAndrew Jeffery int16_t ldst; 243c63f63a2SAndrew Jeffery 244c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 245c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 246c63f63a2SAndrew Jeffery } 247c63f63a2SAndrew Jeffery 248c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 249c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 250c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 251c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 252c63f63a2SAndrew Jeffery } 253c63f63a2SAndrew Jeffery 254c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 255c63f63a2SAndrew Jeffery 256c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 257c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 258c63f63a2SAndrew Jeffery 259c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 260c63f63a2SAndrew Jeffery } 261c63f63a2SAndrew Jeffery 262c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 263c63f63a2SAndrew Jeffery uint32_t *dst) 264c63f63a2SAndrew Jeffery { 265c63f63a2SAndrew Jeffery uint32_t ldst; 266c63f63a2SAndrew Jeffery 267c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 268c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 269c63f63a2SAndrew Jeffery } 270c63f63a2SAndrew Jeffery 271c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 272c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 273c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 274c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 275c63f63a2SAndrew Jeffery } 276c63f63a2SAndrew Jeffery 277c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 278c63f63a2SAndrew Jeffery 279c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 280c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 281c63f63a2SAndrew Jeffery 282c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 283c63f63a2SAndrew Jeffery } 284c63f63a2SAndrew Jeffery 285c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx, 286c63f63a2SAndrew Jeffery int32_t *dst) 287c63f63a2SAndrew Jeffery { 288c63f63a2SAndrew Jeffery int32_t ldst; 289c63f63a2SAndrew Jeffery 290c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 291c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 292c63f63a2SAndrew Jeffery } 293c63f63a2SAndrew Jeffery 294c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 295c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 296c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 297c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 298c63f63a2SAndrew Jeffery } 299c63f63a2SAndrew Jeffery 300c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 301c63f63a2SAndrew Jeffery 302c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 303c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 304c63f63a2SAndrew Jeffery 305c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 306c63f63a2SAndrew Jeffery } 307c63f63a2SAndrew Jeffery 308c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx, 309c63f63a2SAndrew Jeffery real32_t *dst) 310c63f63a2SAndrew Jeffery { 311c63f63a2SAndrew Jeffery uint32_t ldst; 312c63f63a2SAndrew Jeffery 313c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 314c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 315c63f63a2SAndrew Jeffery } 316c63f63a2SAndrew Jeffery 317c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 318c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 319c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 320c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 321c63f63a2SAndrew Jeffery } 322c63f63a2SAndrew Jeffery 323c63f63a2SAndrew Jeffery _Static_assert(sizeof(*dst) == sizeof(ldst), 324c63f63a2SAndrew Jeffery "Mismatched type sizes for dst and ldst"); 325c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 326c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 327c63f63a2SAndrew Jeffery memcpy(dst, &ldst, sizeof(*dst)); 328c63f63a2SAndrew Jeffery ctx->cursor += sizeof(*dst); 329c63f63a2SAndrew Jeffery 330c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 331c63f63a2SAndrew Jeffery } 332c63f63a2SAndrew Jeffery 333c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 33437dd6a3dSAndrew Jeffery _Generic((*(dst)), \ 33537dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_extract_uint8, \ 33637dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_extract_int8, \ 33737dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_extract_uint16, \ 33837dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_extract_int16, \ 33937dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_extract_uint32, \ 34037dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_extract_int32, \ 34137dd6a3dSAndrew Jeffery real32_t: pldm_msgbuf_extract_real32)(ctx, dst) 342c63f63a2SAndrew Jeffery 343369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 344369b121aSAndrew Jeffery uint8_t *dst, size_t count) 345369b121aSAndrew Jeffery { 346369b121aSAndrew Jeffery size_t len; 347369b121aSAndrew Jeffery 348369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 349369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 350369b121aSAndrew Jeffery } 351369b121aSAndrew Jeffery 352369b121aSAndrew Jeffery if (!count) { 353369b121aSAndrew Jeffery return PLDM_SUCCESS; 354369b121aSAndrew Jeffery } 355369b121aSAndrew Jeffery 356369b121aSAndrew Jeffery len = sizeof(*dst) * count; 357369b121aSAndrew Jeffery if (len > SSIZE_MAX) { 358369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 359369b121aSAndrew Jeffery } 360369b121aSAndrew Jeffery 361369b121aSAndrew Jeffery ctx->remaining -= (ssize_t)len; 362369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 363369b121aSAndrew Jeffery if (ctx->remaining < 0) { 364369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 365369b121aSAndrew Jeffery } 366369b121aSAndrew Jeffery 367369b121aSAndrew Jeffery memcpy(dst, ctx->cursor, len); 368369b121aSAndrew Jeffery ctx->cursor += len; 369369b121aSAndrew Jeffery 370369b121aSAndrew Jeffery return PLDM_SUCCESS; 371369b121aSAndrew Jeffery } 372369b121aSAndrew Jeffery 373369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 37437dd6a3dSAndrew Jeffery _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \ 37537dd6a3dSAndrew Jeffery count) 376369b121aSAndrew Jeffery 377062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, 378062c8762SThu Nguyen const uint32_t src) 379062c8762SThu Nguyen { 380062c8762SThu Nguyen uint32_t val = htole32(src); 381062c8762SThu Nguyen 382062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 383062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 384062c8762SThu Nguyen } 385062c8762SThu Nguyen 386062c8762SThu Nguyen ctx->remaining -= sizeof(src); 387062c8762SThu Nguyen assert(ctx->remaining >= 0); 388062c8762SThu Nguyen if (ctx->remaining < 0) { 389062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 390062c8762SThu Nguyen } 391062c8762SThu Nguyen 392062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 393062c8762SThu Nguyen ctx->cursor += sizeof(src); 394062c8762SThu Nguyen 395062c8762SThu Nguyen return PLDM_SUCCESS; 396062c8762SThu Nguyen } 397062c8762SThu Nguyen 398062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, 399062c8762SThu Nguyen const uint16_t src) 400062c8762SThu Nguyen { 401062c8762SThu Nguyen uint16_t val = htole16(src); 402062c8762SThu Nguyen 403062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 404062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 405062c8762SThu Nguyen } 406062c8762SThu Nguyen 407062c8762SThu Nguyen ctx->remaining -= sizeof(src); 408062c8762SThu Nguyen assert(ctx->remaining >= 0); 409062c8762SThu Nguyen if (ctx->remaining < 0) { 410062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 411062c8762SThu Nguyen } 412062c8762SThu Nguyen 413062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 414062c8762SThu Nguyen ctx->cursor += sizeof(src); 415062c8762SThu Nguyen 416062c8762SThu Nguyen return PLDM_SUCCESS; 417062c8762SThu Nguyen } 418062c8762SThu Nguyen 419062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, 420062c8762SThu Nguyen const uint8_t src) 421062c8762SThu Nguyen { 422062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 423062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 424062c8762SThu Nguyen } 425062c8762SThu Nguyen 426062c8762SThu Nguyen ctx->remaining -= sizeof(src); 427062c8762SThu Nguyen assert(ctx->remaining >= 0); 428062c8762SThu Nguyen if (ctx->remaining < 0) { 429062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 430062c8762SThu Nguyen } 431062c8762SThu Nguyen 432062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 433062c8762SThu Nguyen ctx->cursor += sizeof(src); 434062c8762SThu Nguyen 435062c8762SThu Nguyen return PLDM_SUCCESS; 436062c8762SThu Nguyen } 437062c8762SThu Nguyen 438062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, 439062c8762SThu Nguyen const int32_t src) 440062c8762SThu Nguyen { 441062c8762SThu Nguyen int32_t val = htole32(src); 442062c8762SThu Nguyen 443062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 444062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 445062c8762SThu Nguyen } 446062c8762SThu Nguyen 447062c8762SThu Nguyen ctx->remaining -= sizeof(src); 448062c8762SThu Nguyen assert(ctx->remaining >= 0); 449062c8762SThu Nguyen if (ctx->remaining < 0) { 450062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 451062c8762SThu Nguyen } 452062c8762SThu Nguyen 453062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 454062c8762SThu Nguyen ctx->cursor += sizeof(src); 455062c8762SThu Nguyen 456062c8762SThu Nguyen return PLDM_SUCCESS; 457062c8762SThu Nguyen } 458062c8762SThu Nguyen 459062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, 460062c8762SThu Nguyen const int16_t src) 461062c8762SThu Nguyen { 462062c8762SThu Nguyen int16_t val = htole16(src); 463062c8762SThu Nguyen 464062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 465062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 466062c8762SThu Nguyen } 467062c8762SThu Nguyen 468062c8762SThu Nguyen ctx->remaining -= sizeof(src); 469062c8762SThu Nguyen assert(ctx->remaining >= 0); 470062c8762SThu Nguyen if (ctx->remaining < 0) { 471062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 472062c8762SThu Nguyen } 473062c8762SThu Nguyen 474062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 475062c8762SThu Nguyen ctx->cursor += sizeof(src); 476062c8762SThu Nguyen 477062c8762SThu Nguyen return PLDM_SUCCESS; 478062c8762SThu Nguyen } 479062c8762SThu Nguyen 480062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, 481062c8762SThu Nguyen const int8_t src) 482062c8762SThu Nguyen { 483062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 484062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 485062c8762SThu Nguyen } 486062c8762SThu Nguyen 487062c8762SThu Nguyen ctx->remaining -= sizeof(src); 488062c8762SThu Nguyen assert(ctx->remaining >= 0); 489062c8762SThu Nguyen if (ctx->remaining < 0) { 490062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 491062c8762SThu Nguyen } 492062c8762SThu Nguyen 493062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 494062c8762SThu Nguyen ctx->cursor += sizeof(src); 495062c8762SThu Nguyen 496062c8762SThu Nguyen return PLDM_SUCCESS; 497062c8762SThu Nguyen } 498062c8762SThu Nguyen 499062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 50037dd6a3dSAndrew Jeffery _Generic((src), \ 50137dd6a3dSAndrew Jeffery uint8_t: pldm_msgbuf_insert_uint8, \ 50237dd6a3dSAndrew Jeffery int8_t: pldm_msgbuf_insert_int8, \ 50337dd6a3dSAndrew Jeffery uint16_t: pldm_msgbuf_insert_uint16, \ 50437dd6a3dSAndrew Jeffery int16_t: pldm_msgbuf_insert_int16, \ 50537dd6a3dSAndrew Jeffery uint32_t: pldm_msgbuf_insert_uint32, \ 50637dd6a3dSAndrew Jeffery int32_t: pldm_msgbuf_insert_int32)(dst, src) 507062c8762SThu Nguyen 508062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, 509062c8762SThu Nguyen const uint8_t *src, 510062c8762SThu Nguyen size_t count) 511062c8762SThu Nguyen { 512062c8762SThu Nguyen size_t len; 513062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 514062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 515062c8762SThu Nguyen } 516062c8762SThu Nguyen 517062c8762SThu Nguyen if (!count) { 518062c8762SThu Nguyen return PLDM_SUCCESS; 519062c8762SThu Nguyen } 520062c8762SThu Nguyen 521062c8762SThu Nguyen len = sizeof(*src) * count; 522062c8762SThu Nguyen if (len > SSIZE_MAX) { 523062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 524062c8762SThu Nguyen } 525062c8762SThu Nguyen 526062c8762SThu Nguyen ctx->remaining -= (ssize_t)len; 527062c8762SThu Nguyen assert(ctx->remaining >= 0); 528062c8762SThu Nguyen if (ctx->remaining < 0) { 529062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 530062c8762SThu Nguyen } 531062c8762SThu Nguyen 532062c8762SThu Nguyen memcpy(ctx->cursor, src, len); 533062c8762SThu Nguyen ctx->cursor += len; 534062c8762SThu Nguyen 535062c8762SThu Nguyen return PLDM_SUCCESS; 536062c8762SThu Nguyen } 537062c8762SThu Nguyen 538062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 53937dd6a3dSAndrew Jeffery _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \ 54037dd6a3dSAndrew Jeffery count) 541062c8762SThu Nguyen 542062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, 543062c8762SThu Nguyen size_t required, void **cursor) 544062c8762SThu Nguyen { 545062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 546062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 547062c8762SThu Nguyen } 548062c8762SThu Nguyen 549062c8762SThu Nguyen if (required > SSIZE_MAX) { 550062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 551062c8762SThu Nguyen } 552062c8762SThu Nguyen 553062c8762SThu Nguyen ctx->remaining -= (ssize_t)required; 554062c8762SThu Nguyen assert(ctx->remaining >= 0); 555062c8762SThu Nguyen if (ctx->remaining < 0) { 556062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 557062c8762SThu Nguyen } 558062c8762SThu Nguyen 559062c8762SThu Nguyen *cursor = ctx->cursor; 560062c8762SThu Nguyen ctx->cursor += required; 561062c8762SThu Nguyen 562062c8762SThu Nguyen return PLDM_SUCCESS; 563062c8762SThu Nguyen } 564062c8762SThu Nguyen 565062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, 566062c8762SThu Nguyen void **cursor, size_t *len) 567062c8762SThu Nguyen { 568062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 569062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 570062c8762SThu Nguyen } 571062c8762SThu Nguyen 572062c8762SThu Nguyen assert(ctx->remaining >= 0); 573062c8762SThu Nguyen if (ctx->remaining < 0) { 574062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 575062c8762SThu Nguyen } 576062c8762SThu Nguyen 577062c8762SThu Nguyen *cursor = ctx->cursor; 578062c8762SThu Nguyen ctx->cursor += ctx->remaining; 579062c8762SThu Nguyen *len = ctx->remaining; 580062c8762SThu Nguyen ctx->remaining = 0; 581062c8762SThu Nguyen 582062c8762SThu Nguyen return PLDM_SUCCESS; 583062c8762SThu Nguyen } 584c63f63a2SAndrew Jeffery #ifdef __cplusplus 585c63f63a2SAndrew Jeffery } 586c63f63a2SAndrew Jeffery #endif 587c63f63a2SAndrew Jeffery 588c63f63a2SAndrew Jeffery #endif /* BUF_H */ 589