1c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H 2c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H 3c63f63a2SAndrew Jeffery 4c63f63a2SAndrew Jeffery #ifdef __cplusplus 5c63f63a2SAndrew Jeffery extern "C" { 6c63f63a2SAndrew Jeffery #endif 7c63f63a2SAndrew Jeffery 8c63f63a2SAndrew Jeffery #include "base.h" 9c63f63a2SAndrew Jeffery #include "pldm_types.h" 10c63f63a2SAndrew Jeffery 11c63f63a2SAndrew Jeffery #include <assert.h> 12c63f63a2SAndrew Jeffery #include <endian.h> 13c63f63a2SAndrew Jeffery #include <limits.h> 14c63f63a2SAndrew Jeffery #include <stdbool.h> 15c63f63a2SAndrew Jeffery #include <string.h> 16c63f63a2SAndrew Jeffery #include <sys/types.h> 17c63f63a2SAndrew Jeffery 18*062c8762SThu Nguyen /* 19*062c8762SThu Nguyen * Fix up C11's _Static_assert() vs C++'s static_assert(). 20*062c8762SThu Nguyen * 21*062c8762SThu Nguyen * Can we please have nice things for once. 22*062c8762SThu Nguyen */ 23*062c8762SThu Nguyen #ifdef __cplusplus 24*062c8762SThu Nguyen // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 25*062c8762SThu Nguyen #define _Static_assert(...) static_assert(__VA_ARGS__) 26*062c8762SThu Nguyen #endif 27*062c8762SThu Nguyen 28c63f63a2SAndrew Jeffery struct pldm_msgbuf { 29*062c8762SThu Nguyen uint8_t *cursor; 30c63f63a2SAndrew Jeffery ssize_t remaining; 31c63f63a2SAndrew Jeffery }; 32c63f63a2SAndrew Jeffery 33c63f63a2SAndrew Jeffery /** 34c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 35c63f63a2SAndrew Jeffery * 36c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 37c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 38c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 39c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 40c63f63a2SAndrew Jeffery * 41c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 42c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 43c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 44c63f63a2SAndrew Jeffery */ 455646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int 465646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 475646f23bSAndrew Jeffery size_t len) 48c63f63a2SAndrew Jeffery { 49c63f63a2SAndrew Jeffery uint8_t *end; 50c63f63a2SAndrew Jeffery 51c63f63a2SAndrew Jeffery if (!ctx || !buf) { 52c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 53c63f63a2SAndrew Jeffery } 54c63f63a2SAndrew Jeffery 55c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 56c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 57c63f63a2SAndrew Jeffery } 58c63f63a2SAndrew Jeffery 59c63f63a2SAndrew Jeffery end = (uint8_t *)buf + len; 60c63f63a2SAndrew Jeffery if (end && end < (uint8_t *)buf) { 61c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 62c63f63a2SAndrew Jeffery } 63c63f63a2SAndrew Jeffery 64c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 65c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 66c63f63a2SAndrew Jeffery 67c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 68c63f63a2SAndrew Jeffery } 69c63f63a2SAndrew Jeffery 70c63f63a2SAndrew Jeffery /** 71c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 72c63f63a2SAndrew Jeffery * 73c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 74c63f63a2SAndrew Jeffery * 75c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 76c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 77c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 78c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 79c63f63a2SAndrew Jeffery * pointer. 80c63f63a2SAndrew Jeffery */ 81c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 82c63f63a2SAndrew Jeffery { 83c63f63a2SAndrew Jeffery if (!ctx) { 84c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 85c63f63a2SAndrew Jeffery } 86c63f63a2SAndrew Jeffery 87c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 88c63f63a2SAndrew Jeffery } 89c63f63a2SAndrew Jeffery 90c63f63a2SAndrew Jeffery /** 91db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 92db7b8324SAndrew Jeffery * 93db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 94db7b8324SAndrew Jeffery * 95db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 96db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 97db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 98db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 99db7b8324SAndrew Jeffery * pointer. 100db7b8324SAndrew Jeffery */ 101db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 102db7b8324SAndrew Jeffery { 103db7b8324SAndrew Jeffery if (!ctx) { 104db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 105db7b8324SAndrew Jeffery } 106db7b8324SAndrew Jeffery 107db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 108db7b8324SAndrew Jeffery } 109db7b8324SAndrew Jeffery 110db7b8324SAndrew Jeffery /** 111c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 112c63f63a2SAndrew Jeffery * 113c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 114c63f63a2SAndrew Jeffery * 115c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 116c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 117c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 118c63f63a2SAndrew Jeffery * bounds of the buffer. 119c63f63a2SAndrew Jeffery */ 120c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 121c63f63a2SAndrew Jeffery { 122c63f63a2SAndrew Jeffery int valid; 123c63f63a2SAndrew Jeffery 124c63f63a2SAndrew Jeffery if (!ctx) { 125c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 126c63f63a2SAndrew Jeffery } 127c63f63a2SAndrew Jeffery 128c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 129c63f63a2SAndrew Jeffery 130c63f63a2SAndrew Jeffery ctx->cursor = NULL; 131c63f63a2SAndrew Jeffery ctx->remaining = 0; 132c63f63a2SAndrew Jeffery 133c63f63a2SAndrew Jeffery return valid; 134c63f63a2SAndrew Jeffery } 135c63f63a2SAndrew Jeffery 136c63f63a2SAndrew Jeffery /** 137db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 138db7b8324SAndrew Jeffery * has been completely consumed without overflow 139db7b8324SAndrew Jeffery * 140db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 141db7b8324SAndrew Jeffery * 142db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 143db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 144db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 145db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 146db7b8324SAndrew Jeffery */ 147db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 148db7b8324SAndrew Jeffery { 149db7b8324SAndrew Jeffery int consumed; 150db7b8324SAndrew Jeffery 151db7b8324SAndrew Jeffery if (!ctx) { 152db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 153db7b8324SAndrew Jeffery } 154db7b8324SAndrew Jeffery 155db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 156db7b8324SAndrew Jeffery 157db7b8324SAndrew Jeffery ctx->cursor = NULL; 158db7b8324SAndrew Jeffery ctx->remaining = 0; 159db7b8324SAndrew Jeffery 160db7b8324SAndrew Jeffery return consumed; 161db7b8324SAndrew Jeffery } 162db7b8324SAndrew Jeffery 163db7b8324SAndrew Jeffery /** 164c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 165c63f63a2SAndrew Jeffery * 166c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 167c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 168c63f63a2SAndrew Jeffery * 169c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 170c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 171c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 172c63f63a2SAndrew Jeffery */ 173c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx, 174c63f63a2SAndrew Jeffery uint8_t *dst) 175c63f63a2SAndrew Jeffery { 176c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 177c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 178c63f63a2SAndrew Jeffery } 179c63f63a2SAndrew Jeffery 180c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 181c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 182c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 183c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 184c63f63a2SAndrew Jeffery } 185c63f63a2SAndrew Jeffery 186c63f63a2SAndrew Jeffery *dst = *((uint8_t *)(ctx->cursor)); 187c63f63a2SAndrew Jeffery ctx->cursor++; 188c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 189c63f63a2SAndrew Jeffery } 190c63f63a2SAndrew Jeffery 191c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst) 192c63f63a2SAndrew Jeffery { 193c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 194c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 195c63f63a2SAndrew Jeffery } 196c63f63a2SAndrew Jeffery 197c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 198c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 199c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 200c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 201c63f63a2SAndrew Jeffery } 202c63f63a2SAndrew Jeffery 203c63f63a2SAndrew Jeffery *dst = *((int8_t *)(ctx->cursor)); 204c63f63a2SAndrew Jeffery ctx->cursor++; 205c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 206c63f63a2SAndrew Jeffery } 207c63f63a2SAndrew Jeffery 208c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 209c63f63a2SAndrew Jeffery uint16_t *dst) 210c63f63a2SAndrew Jeffery { 211c63f63a2SAndrew Jeffery uint16_t ldst; 212c63f63a2SAndrew Jeffery 213c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 214c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 215c63f63a2SAndrew Jeffery } 216c63f63a2SAndrew Jeffery 217c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 218c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 219c63f63a2SAndrew Jeffery // we've overflowed. 220c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 221c63f63a2SAndrew Jeffery 222c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 223c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 224c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 225c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 226c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 227c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 228c63f63a2SAndrew Jeffery } 229c63f63a2SAndrew Jeffery 230c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 231c63f63a2SAndrew Jeffery // issues on the target architecture 232c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 233c63f63a2SAndrew Jeffery 234c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 235c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 236c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 237c63f63a2SAndrew Jeffery 238c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 239c63f63a2SAndrew Jeffery } 240c63f63a2SAndrew Jeffery 241c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx, 242c63f63a2SAndrew Jeffery int16_t *dst) 243c63f63a2SAndrew Jeffery { 244c63f63a2SAndrew Jeffery int16_t ldst; 245c63f63a2SAndrew Jeffery 246c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 247c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 248c63f63a2SAndrew Jeffery } 249c63f63a2SAndrew Jeffery 250c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 251c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 252c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 253c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 254c63f63a2SAndrew Jeffery } 255c63f63a2SAndrew Jeffery 256c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 257c63f63a2SAndrew Jeffery 258c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 259c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 260c63f63a2SAndrew Jeffery 261c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 262c63f63a2SAndrew Jeffery } 263c63f63a2SAndrew Jeffery 264c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 265c63f63a2SAndrew Jeffery uint32_t *dst) 266c63f63a2SAndrew Jeffery { 267c63f63a2SAndrew Jeffery uint32_t ldst; 268c63f63a2SAndrew Jeffery 269c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 270c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 271c63f63a2SAndrew Jeffery } 272c63f63a2SAndrew Jeffery 273c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 274c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 275c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 276c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 277c63f63a2SAndrew Jeffery } 278c63f63a2SAndrew Jeffery 279c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 280c63f63a2SAndrew Jeffery 281c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 282c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 283c63f63a2SAndrew Jeffery 284c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 285c63f63a2SAndrew Jeffery } 286c63f63a2SAndrew Jeffery 287c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx, 288c63f63a2SAndrew Jeffery int32_t *dst) 289c63f63a2SAndrew Jeffery { 290c63f63a2SAndrew Jeffery int32_t ldst; 291c63f63a2SAndrew Jeffery 292c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 293c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 294c63f63a2SAndrew Jeffery } 295c63f63a2SAndrew Jeffery 296c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 297c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 298c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 299c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 300c63f63a2SAndrew Jeffery } 301c63f63a2SAndrew Jeffery 302c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 303c63f63a2SAndrew Jeffery 304c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 305c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 306c63f63a2SAndrew Jeffery 307c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 308c63f63a2SAndrew Jeffery } 309c63f63a2SAndrew Jeffery 310c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx, 311c63f63a2SAndrew Jeffery real32_t *dst) 312c63f63a2SAndrew Jeffery { 313c63f63a2SAndrew Jeffery uint32_t ldst; 314c63f63a2SAndrew Jeffery 315c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 316c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 317c63f63a2SAndrew Jeffery } 318c63f63a2SAndrew Jeffery 319c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 320c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 321c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 322c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 323c63f63a2SAndrew Jeffery } 324c63f63a2SAndrew Jeffery 325c63f63a2SAndrew Jeffery _Static_assert(sizeof(*dst) == sizeof(ldst), 326c63f63a2SAndrew Jeffery "Mismatched type sizes for dst and ldst"); 327c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 328c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 329c63f63a2SAndrew Jeffery memcpy(dst, &ldst, sizeof(*dst)); 330c63f63a2SAndrew Jeffery ctx->cursor += sizeof(*dst); 331c63f63a2SAndrew Jeffery 332c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 333c63f63a2SAndrew Jeffery } 334c63f63a2SAndrew Jeffery 335c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 336c63f63a2SAndrew Jeffery _Generic((*(dst)), uint8_t \ 337c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint8, int8_t \ 338c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int8, uint16_t \ 339c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint16, int16_t \ 340c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int16, uint32_t \ 341c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint32, int32_t \ 342c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int32, real32_t \ 343c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_real32)(ctx, dst) 344c63f63a2SAndrew Jeffery 345369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 346369b121aSAndrew Jeffery uint8_t *dst, size_t count) 347369b121aSAndrew Jeffery { 348369b121aSAndrew Jeffery size_t len; 349369b121aSAndrew Jeffery 350369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 351369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 352369b121aSAndrew Jeffery } 353369b121aSAndrew Jeffery 354369b121aSAndrew Jeffery if (!count) { 355369b121aSAndrew Jeffery return PLDM_SUCCESS; 356369b121aSAndrew Jeffery } 357369b121aSAndrew Jeffery 358369b121aSAndrew Jeffery len = sizeof(*dst) * count; 359369b121aSAndrew Jeffery if (len > SSIZE_MAX) { 360369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 361369b121aSAndrew Jeffery } 362369b121aSAndrew Jeffery 363369b121aSAndrew Jeffery ctx->remaining -= (ssize_t)len; 364369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 365369b121aSAndrew Jeffery if (ctx->remaining < 0) { 366369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 367369b121aSAndrew Jeffery } 368369b121aSAndrew Jeffery 369369b121aSAndrew Jeffery memcpy(dst, ctx->cursor, len); 370369b121aSAndrew Jeffery ctx->cursor += len; 371369b121aSAndrew Jeffery 372369b121aSAndrew Jeffery return PLDM_SUCCESS; 373369b121aSAndrew Jeffery } 374369b121aSAndrew Jeffery 375369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 376369b121aSAndrew Jeffery _Generic((*(dst)), uint8_t \ 377369b121aSAndrew Jeffery : pldm_msgbuf_extract_array_uint8)(ctx, dst, count) 378369b121aSAndrew Jeffery 379*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, 380*062c8762SThu Nguyen const uint32_t src) 381*062c8762SThu Nguyen { 382*062c8762SThu Nguyen uint32_t val = htole32(src); 383*062c8762SThu Nguyen 384*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 385*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 386*062c8762SThu Nguyen } 387*062c8762SThu Nguyen 388*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 389*062c8762SThu Nguyen assert(ctx->remaining >= 0); 390*062c8762SThu Nguyen if (ctx->remaining < 0) { 391*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 392*062c8762SThu Nguyen } 393*062c8762SThu Nguyen 394*062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 395*062c8762SThu Nguyen ctx->cursor += sizeof(src); 396*062c8762SThu Nguyen 397*062c8762SThu Nguyen return PLDM_SUCCESS; 398*062c8762SThu Nguyen } 399*062c8762SThu Nguyen 400*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, 401*062c8762SThu Nguyen const uint16_t src) 402*062c8762SThu Nguyen { 403*062c8762SThu Nguyen uint16_t val = htole16(src); 404*062c8762SThu Nguyen 405*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 406*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 407*062c8762SThu Nguyen } 408*062c8762SThu Nguyen 409*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 410*062c8762SThu Nguyen assert(ctx->remaining >= 0); 411*062c8762SThu Nguyen if (ctx->remaining < 0) { 412*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 413*062c8762SThu Nguyen } 414*062c8762SThu Nguyen 415*062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 416*062c8762SThu Nguyen ctx->cursor += sizeof(src); 417*062c8762SThu Nguyen 418*062c8762SThu Nguyen return PLDM_SUCCESS; 419*062c8762SThu Nguyen } 420*062c8762SThu Nguyen 421*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, 422*062c8762SThu Nguyen const uint8_t src) 423*062c8762SThu Nguyen { 424*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 425*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 426*062c8762SThu Nguyen } 427*062c8762SThu Nguyen 428*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 429*062c8762SThu Nguyen assert(ctx->remaining >= 0); 430*062c8762SThu Nguyen if (ctx->remaining < 0) { 431*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 432*062c8762SThu Nguyen } 433*062c8762SThu Nguyen 434*062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 435*062c8762SThu Nguyen ctx->cursor += sizeof(src); 436*062c8762SThu Nguyen 437*062c8762SThu Nguyen return PLDM_SUCCESS; 438*062c8762SThu Nguyen } 439*062c8762SThu Nguyen 440*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, 441*062c8762SThu Nguyen const int32_t src) 442*062c8762SThu Nguyen { 443*062c8762SThu Nguyen int32_t val = htole32(src); 444*062c8762SThu Nguyen 445*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 446*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 447*062c8762SThu Nguyen } 448*062c8762SThu Nguyen 449*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 450*062c8762SThu Nguyen assert(ctx->remaining >= 0); 451*062c8762SThu Nguyen if (ctx->remaining < 0) { 452*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 453*062c8762SThu Nguyen } 454*062c8762SThu Nguyen 455*062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 456*062c8762SThu Nguyen ctx->cursor += sizeof(src); 457*062c8762SThu Nguyen 458*062c8762SThu Nguyen return PLDM_SUCCESS; 459*062c8762SThu Nguyen } 460*062c8762SThu Nguyen 461*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, 462*062c8762SThu Nguyen const int16_t src) 463*062c8762SThu Nguyen { 464*062c8762SThu Nguyen int16_t val = htole16(src); 465*062c8762SThu Nguyen 466*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 467*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 468*062c8762SThu Nguyen } 469*062c8762SThu Nguyen 470*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 471*062c8762SThu Nguyen assert(ctx->remaining >= 0); 472*062c8762SThu Nguyen if (ctx->remaining < 0) { 473*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 474*062c8762SThu Nguyen } 475*062c8762SThu Nguyen 476*062c8762SThu Nguyen memcpy(ctx->cursor, &val, sizeof(val)); 477*062c8762SThu Nguyen ctx->cursor += sizeof(src); 478*062c8762SThu Nguyen 479*062c8762SThu Nguyen return PLDM_SUCCESS; 480*062c8762SThu Nguyen } 481*062c8762SThu Nguyen 482*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, 483*062c8762SThu Nguyen const int8_t src) 484*062c8762SThu Nguyen { 485*062c8762SThu Nguyen if (!ctx || !ctx->cursor) { 486*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 487*062c8762SThu Nguyen } 488*062c8762SThu Nguyen 489*062c8762SThu Nguyen ctx->remaining -= sizeof(src); 490*062c8762SThu Nguyen assert(ctx->remaining >= 0); 491*062c8762SThu Nguyen if (ctx->remaining < 0) { 492*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 493*062c8762SThu Nguyen } 494*062c8762SThu Nguyen 495*062c8762SThu Nguyen memcpy(ctx->cursor, &src, sizeof(src)); 496*062c8762SThu Nguyen ctx->cursor += sizeof(src); 497*062c8762SThu Nguyen 498*062c8762SThu Nguyen return PLDM_SUCCESS; 499*062c8762SThu Nguyen } 500*062c8762SThu Nguyen 501*062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src) \ 502*062c8762SThu Nguyen _Generic((src), uint8_t \ 503*062c8762SThu Nguyen : pldm_msgbuf_insert_uint8, int8_t \ 504*062c8762SThu Nguyen : pldm_msgbuf_insert_int8, uint16_t \ 505*062c8762SThu Nguyen : pldm_msgbuf_insert_uint16, int16_t \ 506*062c8762SThu Nguyen : pldm_msgbuf_insert_int16, uint32_t \ 507*062c8762SThu Nguyen : pldm_msgbuf_insert_uint32, int32_t \ 508*062c8762SThu Nguyen : pldm_msgbuf_insert_int32)(dst, src) 509*062c8762SThu Nguyen 510*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, 511*062c8762SThu Nguyen const uint8_t *src, 512*062c8762SThu Nguyen size_t count) 513*062c8762SThu Nguyen { 514*062c8762SThu Nguyen size_t len; 515*062c8762SThu Nguyen if (!ctx || !ctx->cursor || !src) { 516*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 517*062c8762SThu Nguyen } 518*062c8762SThu Nguyen 519*062c8762SThu Nguyen if (!count) { 520*062c8762SThu Nguyen return PLDM_SUCCESS; 521*062c8762SThu Nguyen } 522*062c8762SThu Nguyen 523*062c8762SThu Nguyen len = sizeof(*src) * count; 524*062c8762SThu Nguyen if (len > SSIZE_MAX) { 525*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 526*062c8762SThu Nguyen } 527*062c8762SThu Nguyen 528*062c8762SThu Nguyen ctx->remaining -= (ssize_t)len; 529*062c8762SThu Nguyen assert(ctx->remaining >= 0); 530*062c8762SThu Nguyen if (ctx->remaining < 0) { 531*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 532*062c8762SThu Nguyen } 533*062c8762SThu Nguyen 534*062c8762SThu Nguyen memcpy(ctx->cursor, src, len); 535*062c8762SThu Nguyen ctx->cursor += len; 536*062c8762SThu Nguyen 537*062c8762SThu Nguyen return PLDM_SUCCESS; 538*062c8762SThu Nguyen } 539*062c8762SThu Nguyen 540*062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count) \ 541*062c8762SThu Nguyen _Generic((*(src)), uint8_t \ 542*062c8762SThu Nguyen : pldm_msgbuf_insert_array_uint8)(dst, src, count) 543*062c8762SThu Nguyen 544*062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, 545*062c8762SThu Nguyen size_t required, void **cursor) 546*062c8762SThu Nguyen { 547*062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor) { 548*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 549*062c8762SThu Nguyen } 550*062c8762SThu Nguyen 551*062c8762SThu Nguyen if (required > SSIZE_MAX) { 552*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 553*062c8762SThu Nguyen } 554*062c8762SThu Nguyen 555*062c8762SThu Nguyen ctx->remaining -= (ssize_t)required; 556*062c8762SThu Nguyen assert(ctx->remaining >= 0); 557*062c8762SThu Nguyen if (ctx->remaining < 0) { 558*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 559*062c8762SThu Nguyen } 560*062c8762SThu Nguyen 561*062c8762SThu Nguyen *cursor = ctx->cursor; 562*062c8762SThu Nguyen ctx->cursor += required; 563*062c8762SThu Nguyen 564*062c8762SThu Nguyen return PLDM_SUCCESS; 565*062c8762SThu Nguyen } 566*062c8762SThu Nguyen 567*062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, 568*062c8762SThu Nguyen void **cursor, size_t *len) 569*062c8762SThu Nguyen { 570*062c8762SThu Nguyen if (!ctx || !ctx->cursor || !cursor || *cursor || !len) { 571*062c8762SThu Nguyen return PLDM_ERROR_INVALID_DATA; 572*062c8762SThu Nguyen } 573*062c8762SThu Nguyen 574*062c8762SThu Nguyen assert(ctx->remaining >= 0); 575*062c8762SThu Nguyen if (ctx->remaining < 0) { 576*062c8762SThu Nguyen return PLDM_ERROR_INVALID_LENGTH; 577*062c8762SThu Nguyen } 578*062c8762SThu Nguyen 579*062c8762SThu Nguyen *cursor = ctx->cursor; 580*062c8762SThu Nguyen ctx->cursor += ctx->remaining; 581*062c8762SThu Nguyen *len = ctx->remaining; 582*062c8762SThu Nguyen ctx->remaining = 0; 583*062c8762SThu Nguyen 584*062c8762SThu Nguyen return PLDM_SUCCESS; 585*062c8762SThu Nguyen } 586c63f63a2SAndrew Jeffery #ifdef __cplusplus 587c63f63a2SAndrew Jeffery } 588c63f63a2SAndrew Jeffery #endif 589c63f63a2SAndrew Jeffery 590c63f63a2SAndrew Jeffery #endif /* BUF_H */ 591