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 18c63f63a2SAndrew Jeffery struct pldm_msgbuf { 19c63f63a2SAndrew Jeffery const uint8_t *cursor; 20c63f63a2SAndrew Jeffery ssize_t remaining; 21c63f63a2SAndrew Jeffery }; 22c63f63a2SAndrew Jeffery 23c63f63a2SAndrew Jeffery /** 24c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 25c63f63a2SAndrew Jeffery * 26c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 27c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 28c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 29c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 30c63f63a2SAndrew Jeffery * 31c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 32c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 33c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 34c63f63a2SAndrew Jeffery */ 355646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int 365646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 375646f23bSAndrew Jeffery size_t len) 38c63f63a2SAndrew Jeffery { 39c63f63a2SAndrew Jeffery uint8_t *end; 40c63f63a2SAndrew Jeffery 41c63f63a2SAndrew Jeffery if (!ctx || !buf) { 42c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 43c63f63a2SAndrew Jeffery } 44c63f63a2SAndrew Jeffery 45c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 46c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 47c63f63a2SAndrew Jeffery } 48c63f63a2SAndrew Jeffery 49c63f63a2SAndrew Jeffery end = (uint8_t *)buf + len; 50c63f63a2SAndrew Jeffery if (end && end < (uint8_t *)buf) { 51c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 52c63f63a2SAndrew Jeffery } 53c63f63a2SAndrew Jeffery 54c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 55c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 56c63f63a2SAndrew Jeffery 57c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 58c63f63a2SAndrew Jeffery } 59c63f63a2SAndrew Jeffery 60c63f63a2SAndrew Jeffery /** 61c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 62c63f63a2SAndrew Jeffery * 63c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 64c63f63a2SAndrew Jeffery * 65c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 66c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 67c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 68c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 69c63f63a2SAndrew Jeffery * pointer. 70c63f63a2SAndrew Jeffery */ 71c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 72c63f63a2SAndrew Jeffery { 73c63f63a2SAndrew Jeffery if (!ctx) { 74c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 75c63f63a2SAndrew Jeffery } 76c63f63a2SAndrew Jeffery 77c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 78c63f63a2SAndrew Jeffery } 79c63f63a2SAndrew Jeffery 80c63f63a2SAndrew Jeffery /** 81*db7b8324SAndrew Jeffery * @brief Test whether a message buffer has been exactly consumed 82*db7b8324SAndrew Jeffery * 83*db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 84*db7b8324SAndrew Jeffery * 85*db7b8324SAndrew Jeffery * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from 86*db7b8324SAndrew Jeffery * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH 87*db7b8324SAndrew Jeffery * indicates that an incorrect sequence of accesses have occurred, and 88*db7b8324SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 89*db7b8324SAndrew Jeffery * pointer. 90*db7b8324SAndrew Jeffery */ 91*db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx) 92*db7b8324SAndrew Jeffery { 93*db7b8324SAndrew Jeffery if (!ctx) { 94*db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 95*db7b8324SAndrew Jeffery } 96*db7b8324SAndrew Jeffery 97*db7b8324SAndrew Jeffery return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 98*db7b8324SAndrew Jeffery } 99*db7b8324SAndrew Jeffery 100*db7b8324SAndrew Jeffery /** 101c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 102c63f63a2SAndrew Jeffery * 103c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 104c63f63a2SAndrew Jeffery * 105c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 106c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 107c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 108c63f63a2SAndrew Jeffery * bounds of the buffer. 109c63f63a2SAndrew Jeffery */ 110c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 111c63f63a2SAndrew Jeffery { 112c63f63a2SAndrew Jeffery int valid; 113c63f63a2SAndrew Jeffery 114c63f63a2SAndrew Jeffery if (!ctx) { 115c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 116c63f63a2SAndrew Jeffery } 117c63f63a2SAndrew Jeffery 118c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 119c63f63a2SAndrew Jeffery 120c63f63a2SAndrew Jeffery ctx->cursor = NULL; 121c63f63a2SAndrew Jeffery ctx->remaining = 0; 122c63f63a2SAndrew Jeffery 123c63f63a2SAndrew Jeffery return valid; 124c63f63a2SAndrew Jeffery } 125c63f63a2SAndrew Jeffery 126c63f63a2SAndrew Jeffery /** 127*db7b8324SAndrew Jeffery * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer 128*db7b8324SAndrew Jeffery * has been completely consumed without overflow 129*db7b8324SAndrew Jeffery * 130*db7b8324SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context 131*db7b8324SAndrew Jeffery * 132*db7b8324SAndrew Jeffery * @return PLDM_SUCCESS if all buffer access were in-bounds and completely 133*db7b8324SAndrew Jeffery * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx 134*db7b8324SAndrew Jeffery * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would 135*db7b8324SAndrew Jeffery * have occurred byond the bounds of the buffer 136*db7b8324SAndrew Jeffery */ 137*db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx) 138*db7b8324SAndrew Jeffery { 139*db7b8324SAndrew Jeffery int consumed; 140*db7b8324SAndrew Jeffery 141*db7b8324SAndrew Jeffery if (!ctx) { 142*db7b8324SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 143*db7b8324SAndrew Jeffery } 144*db7b8324SAndrew Jeffery 145*db7b8324SAndrew Jeffery consumed = pldm_msgbuf_consumed(ctx); 146*db7b8324SAndrew Jeffery 147*db7b8324SAndrew Jeffery ctx->cursor = NULL; 148*db7b8324SAndrew Jeffery ctx->remaining = 0; 149*db7b8324SAndrew Jeffery 150*db7b8324SAndrew Jeffery return consumed; 151*db7b8324SAndrew Jeffery } 152*db7b8324SAndrew Jeffery 153*db7b8324SAndrew Jeffery /** 154c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 155c63f63a2SAndrew Jeffery * 156c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 157c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 158c63f63a2SAndrew Jeffery * 159c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 160c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 161c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 162c63f63a2SAndrew Jeffery */ 163c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx, 164c63f63a2SAndrew Jeffery uint8_t *dst) 165c63f63a2SAndrew Jeffery { 166c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 167c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 168c63f63a2SAndrew Jeffery } 169c63f63a2SAndrew Jeffery 170c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 171c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 172c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 173c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 174c63f63a2SAndrew Jeffery } 175c63f63a2SAndrew Jeffery 176c63f63a2SAndrew Jeffery *dst = *((uint8_t *)(ctx->cursor)); 177c63f63a2SAndrew Jeffery ctx->cursor++; 178c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 179c63f63a2SAndrew Jeffery } 180c63f63a2SAndrew Jeffery 181c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_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 = *((int8_t *)(ctx->cursor)); 194c63f63a2SAndrew Jeffery ctx->cursor++; 195c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 196c63f63a2SAndrew Jeffery } 197c63f63a2SAndrew Jeffery 198c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 199c63f63a2SAndrew Jeffery uint16_t *dst) 200c63f63a2SAndrew Jeffery { 201c63f63a2SAndrew Jeffery uint16_t ldst; 202c63f63a2SAndrew Jeffery 203c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 204c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 205c63f63a2SAndrew Jeffery } 206c63f63a2SAndrew Jeffery 207c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 208c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 209c63f63a2SAndrew Jeffery // we've overflowed. 210c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 211c63f63a2SAndrew Jeffery 212c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 213c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 214c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 215c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 216c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 217c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 218c63f63a2SAndrew Jeffery } 219c63f63a2SAndrew Jeffery 220c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 221c63f63a2SAndrew Jeffery // issues on the target architecture 222c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 223c63f63a2SAndrew Jeffery 224c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 225c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 226c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 227c63f63a2SAndrew Jeffery 228c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 229c63f63a2SAndrew Jeffery } 230c63f63a2SAndrew Jeffery 231c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx, 232c63f63a2SAndrew Jeffery int16_t *dst) 233c63f63a2SAndrew Jeffery { 234c63f63a2SAndrew Jeffery int16_t ldst; 235c63f63a2SAndrew Jeffery 236c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 237c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 238c63f63a2SAndrew Jeffery } 239c63f63a2SAndrew Jeffery 240c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 241c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 242c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 243c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 244c63f63a2SAndrew Jeffery } 245c63f63a2SAndrew Jeffery 246c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 247c63f63a2SAndrew Jeffery 248c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 249c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 250c63f63a2SAndrew Jeffery 251c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 252c63f63a2SAndrew Jeffery } 253c63f63a2SAndrew Jeffery 254c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 255c63f63a2SAndrew Jeffery uint32_t *dst) 256c63f63a2SAndrew Jeffery { 257c63f63a2SAndrew Jeffery uint32_t ldst; 258c63f63a2SAndrew Jeffery 259c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 260c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 261c63f63a2SAndrew Jeffery } 262c63f63a2SAndrew Jeffery 263c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 264c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 265c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 266c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 267c63f63a2SAndrew Jeffery } 268c63f63a2SAndrew Jeffery 269c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 270c63f63a2SAndrew Jeffery 271c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 272c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 273c63f63a2SAndrew Jeffery 274c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 275c63f63a2SAndrew Jeffery } 276c63f63a2SAndrew Jeffery 277c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx, 278c63f63a2SAndrew Jeffery int32_t *dst) 279c63f63a2SAndrew Jeffery { 280c63f63a2SAndrew Jeffery int32_t ldst; 281c63f63a2SAndrew Jeffery 282c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 283c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 284c63f63a2SAndrew Jeffery } 285c63f63a2SAndrew Jeffery 286c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 287c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 288c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 289c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 290c63f63a2SAndrew Jeffery } 291c63f63a2SAndrew Jeffery 292c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 293c63f63a2SAndrew Jeffery 294c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 295c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 296c63f63a2SAndrew Jeffery 297c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 298c63f63a2SAndrew Jeffery } 299c63f63a2SAndrew Jeffery 300c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx, 301c63f63a2SAndrew Jeffery real32_t *dst) 302c63f63a2SAndrew Jeffery { 303c63f63a2SAndrew Jeffery uint32_t ldst; 304c63f63a2SAndrew Jeffery 305c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 306c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 307c63f63a2SAndrew Jeffery } 308c63f63a2SAndrew Jeffery 309c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 310c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 311c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 312c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 313c63f63a2SAndrew Jeffery } 314c63f63a2SAndrew Jeffery 315c63f63a2SAndrew Jeffery _Static_assert(sizeof(*dst) == sizeof(ldst), 316c63f63a2SAndrew Jeffery "Mismatched type sizes for dst and ldst"); 317c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 318c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 319c63f63a2SAndrew Jeffery memcpy(dst, &ldst, sizeof(*dst)); 320c63f63a2SAndrew Jeffery ctx->cursor += sizeof(*dst); 321c63f63a2SAndrew Jeffery 322c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 323c63f63a2SAndrew Jeffery } 324c63f63a2SAndrew Jeffery 325c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 326c63f63a2SAndrew Jeffery _Generic((*(dst)), uint8_t \ 327c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint8, int8_t \ 328c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int8, uint16_t \ 329c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint16, int16_t \ 330c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int16, uint32_t \ 331c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint32, int32_t \ 332c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int32, real32_t \ 333c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_real32)(ctx, dst) 334c63f63a2SAndrew Jeffery 335369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 336369b121aSAndrew Jeffery uint8_t *dst, size_t count) 337369b121aSAndrew Jeffery { 338369b121aSAndrew Jeffery size_t len; 339369b121aSAndrew Jeffery 340369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 341369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 342369b121aSAndrew Jeffery } 343369b121aSAndrew Jeffery 344369b121aSAndrew Jeffery if (!count) { 345369b121aSAndrew Jeffery return PLDM_SUCCESS; 346369b121aSAndrew Jeffery } 347369b121aSAndrew Jeffery 348369b121aSAndrew Jeffery len = sizeof(*dst) * count; 349369b121aSAndrew Jeffery if (len > SSIZE_MAX) { 350369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 351369b121aSAndrew Jeffery } 352369b121aSAndrew Jeffery 353369b121aSAndrew Jeffery ctx->remaining -= (ssize_t)len; 354369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 355369b121aSAndrew Jeffery if (ctx->remaining < 0) { 356369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 357369b121aSAndrew Jeffery } 358369b121aSAndrew Jeffery 359369b121aSAndrew Jeffery memcpy(dst, ctx->cursor, len); 360369b121aSAndrew Jeffery ctx->cursor += len; 361369b121aSAndrew Jeffery 362369b121aSAndrew Jeffery return PLDM_SUCCESS; 363369b121aSAndrew Jeffery } 364369b121aSAndrew Jeffery 365369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 366369b121aSAndrew Jeffery _Generic((*(dst)), uint8_t \ 367369b121aSAndrew Jeffery : pldm_msgbuf_extract_array_uint8)(ctx, dst, count) 368369b121aSAndrew Jeffery 369c63f63a2SAndrew Jeffery #ifdef __cplusplus 370c63f63a2SAndrew Jeffery } 371c63f63a2SAndrew Jeffery #endif 372c63f63a2SAndrew Jeffery 373c63f63a2SAndrew Jeffery #endif /* BUF_H */ 374