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