xref: /openbmc/libpldm/src/msgbuf.h (revision 8f3b13c46f0e6b7e67bc2f8d1451db4c1054d394)
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 
5860a43d9SAndrew Jeffery #include "compiler.h"
6860a43d9SAndrew Jeffery 
766c7723aSAndrew Jeffery /*
866c7723aSAndrew Jeffery  * Historically, many of the structs exposed in libpldm's public headers are
966c7723aSAndrew Jeffery  * defined with __attribute__((packed)). This is unfortunate: it gives the
1066c7723aSAndrew Jeffery  * impression that a wire-format buffer can be cast to the message type to make
1166c7723aSAndrew Jeffery  * the message's fields easily accessible. As it turns out, that's not
1266c7723aSAndrew Jeffery  * that's valid for several reasons:
1366c7723aSAndrew Jeffery  *
1466c7723aSAndrew Jeffery  * 1. Casting the wire-format buffer to a struct of the message type doesn't
1566c7723aSAndrew Jeffery  *    abstract the endianness of message field values
1666c7723aSAndrew Jeffery  *
1766c7723aSAndrew Jeffery  * 2. Some messages contain packed tagged union fields which cannot be properly
1866c7723aSAndrew Jeffery  *    described in a C struct.
1966c7723aSAndrew Jeffery  *
2066c7723aSAndrew Jeffery  * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
2166c7723aSAndrew Jeffery  * that is type-safe, spatially memory-safe, endian-safe, performant, and
2266c7723aSAndrew Jeffery  * free of undefined-behaviour. Message structs that are added to the public
2366c7723aSAndrew Jeffery  * library API should no-longer be marked __attribute__((packed)), and the
2466c7723aSAndrew Jeffery  * implementation of their encode and decode functions must exploit the msgbuf
2566c7723aSAndrew Jeffery  * API.
2666c7723aSAndrew Jeffery  *
2766c7723aSAndrew Jeffery  * However, we would like to allow implementation of codec functions in terms of
2866c7723aSAndrew Jeffery  * msgbuf APIs even if they're decoding a message into a (historically) packed
2966c7723aSAndrew Jeffery  * struct. Some of the complexity that follows is a consequence of the packed/
3066c7723aSAndrew Jeffery  * unpacked conflict.
3166c7723aSAndrew Jeffery  */
3266c7723aSAndrew Jeffery 
33c63f63a2SAndrew Jeffery #ifdef __cplusplus
3437dd6a3dSAndrew Jeffery /*
3537dd6a3dSAndrew Jeffery  * Fix up C11's _Static_assert() vs C++'s static_assert().
3637dd6a3dSAndrew Jeffery  *
3737dd6a3dSAndrew Jeffery  * Can we please have nice things for once.
3837dd6a3dSAndrew Jeffery  */
3937dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
4037dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__)
41c63f63a2SAndrew Jeffery extern "C" {
42c63f63a2SAndrew Jeffery #endif
43c63f63a2SAndrew Jeffery 
44b0c1d20aSAndrew Jeffery #include <libpldm/base.h>
45b0c1d20aSAndrew Jeffery #include <libpldm/pldm_types.h>
46c63f63a2SAndrew Jeffery 
4766c7723aSAndrew Jeffery #include "compiler.h"
4866c7723aSAndrew Jeffery 
49c63f63a2SAndrew Jeffery #include <assert.h>
50c63f63a2SAndrew Jeffery #include <endian.h>
51c8df31c1SAndrew Jeffery #include <errno.h>
52c63f63a2SAndrew Jeffery #include <limits.h>
53c63f63a2SAndrew Jeffery #include <stdbool.h>
5466c7723aSAndrew Jeffery #include <stdint.h>
55c63f63a2SAndrew Jeffery #include <string.h>
56c63f63a2SAndrew Jeffery #include <sys/types.h>
571523778dSThu Nguyen #include <uchar.h>
58c63f63a2SAndrew Jeffery 
592ff8cf89SAndrew Jeffery /*
602ff8cf89SAndrew Jeffery  * We can't use static_assert() outside of some other C construct. Deal
612ff8cf89SAndrew Jeffery  * with high-level global assertions by burying them in an unused struct
622ff8cf89SAndrew Jeffery  * declaration, that has a sole member for compliance with the requirement that
632ff8cf89SAndrew Jeffery  * types must have a size.
642ff8cf89SAndrew Jeffery */
652ff8cf89SAndrew Jeffery static struct {
662ff8cf89SAndrew Jeffery 	static_assert(
672ff8cf89SAndrew Jeffery 		INTMAX_MAX != SIZE_MAX,
682ff8cf89SAndrew Jeffery 		"Extraction and insertion value comparisons may be broken");
692ff8cf89SAndrew Jeffery 	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
702ff8cf89SAndrew Jeffery 		      "Extraction and insertion arithmetic may be broken");
712ff8cf89SAndrew Jeffery 	int compliance;
72860a43d9SAndrew Jeffery } build_assertions LIBPLDM_CC_UNUSED;
732ff8cf89SAndrew Jeffery 
74c63f63a2SAndrew Jeffery struct pldm_msgbuf {
75062c8762SThu Nguyen 	uint8_t *cursor;
762ff8cf89SAndrew Jeffery 	intmax_t remaining;
77c63f63a2SAndrew Jeffery };
78c63f63a2SAndrew Jeffery 
79d861a681SAndrew Jeffery /**
80c63f63a2SAndrew Jeffery  * @brief Initialize pldm buf struct for buf extractor
81c63f63a2SAndrew Jeffery  *
82c63f63a2SAndrew Jeffery  * @param[out] ctx - pldm_msgbuf context for extractor
83c63f63a2SAndrew Jeffery  * @param[in] minsize - The minimum required length of buffer `buf`
84c63f63a2SAndrew Jeffery  * @param[in] buf - buffer to be extracted
85c63f63a2SAndrew Jeffery  * @param[in] len - size of buffer
86c63f63a2SAndrew Jeffery  *
87c8df31c1SAndrew Jeffery  * @return 0 on success, otherwise an error code appropriate for the current
88c8df31c1SAndrew Jeffery  *         personality.
89c63f63a2SAndrew Jeffery  */
9090bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
91cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
92c8df31c1SAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm_msgbuf_init_errno(struct pldm_msgbuf * ctx,size_t minsize,const void * buf,size_t len)93830c1eb4SAndrew Jeffery pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
9476712f69SAndrew Jeffery 		       size_t len)
95c63f63a2SAndrew Jeffery {
962ff8cf89SAndrew Jeffery 	if ((minsize > len)) {
97830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
98c63f63a2SAndrew Jeffery 	}
99c63f63a2SAndrew Jeffery 
1002ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
1012ff8cf89SAndrew Jeffery 	if (len > INTMAX_MAX) {
102830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
1032ff8cf89SAndrew Jeffery 	}
1042ff8cf89SAndrew Jeffery #endif
1052ff8cf89SAndrew Jeffery 
1064f60fb77SAndrew Jeffery 	if (UINTPTR_MAX - (uintptr_t)buf < len) {
107830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
108c63f63a2SAndrew Jeffery 	}
109c63f63a2SAndrew Jeffery 
110c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
1112ff8cf89SAndrew Jeffery 	ctx->remaining = (intmax_t)len;
112c63f63a2SAndrew Jeffery 
113c8df31c1SAndrew Jeffery 	return 0;
114c8df31c1SAndrew Jeffery }
115c8df31c1SAndrew Jeffery 
116c8df31c1SAndrew Jeffery /**
117c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
118c63f63a2SAndrew Jeffery  *
119c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
120c63f63a2SAndrew Jeffery  *
121c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
122c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
123c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
124c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
125c63f63a2SAndrew Jeffery  * pointer.
126c63f63a2SAndrew Jeffery  */
12790bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_validate(struct pldm_msgbuf * ctx)128cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
129c63f63a2SAndrew Jeffery {
130c8df31c1SAndrew Jeffery 	if (ctx->remaining < 0) {
131830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
132c63f63a2SAndrew Jeffery 	}
133c63f63a2SAndrew Jeffery 
134c8df31c1SAndrew Jeffery 	return 0;
135c63f63a2SAndrew Jeffery }
136c63f63a2SAndrew Jeffery 
137c63f63a2SAndrew Jeffery /**
138db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
139db7b8324SAndrew Jeffery  *
140db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
141db7b8324SAndrew Jeffery  *
142db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
143db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
144db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
145db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
146db7b8324SAndrew Jeffery  * pointer.
147db7b8324SAndrew Jeffery  */
14890bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_consumed(struct pldm_msgbuf * ctx)149cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
150db7b8324SAndrew Jeffery {
151c8df31c1SAndrew Jeffery 	if (ctx->remaining != 0) {
152830c1eb4SAndrew Jeffery 		return -EBADMSG;
153db7b8324SAndrew Jeffery 	}
154db7b8324SAndrew Jeffery 
155c8df31c1SAndrew Jeffery 	return 0;
156db7b8324SAndrew Jeffery }
157db7b8324SAndrew Jeffery 
158db7b8324SAndrew Jeffery /**
159c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
160c63f63a2SAndrew Jeffery  *
161c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
162c63f63a2SAndrew Jeffery  *
163c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
164c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
165c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
166c63f63a2SAndrew Jeffery  * bounds of the buffer.
167c63f63a2SAndrew Jeffery  */
16890bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_destroy(struct pldm_msgbuf * ctx)169cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
170c63f63a2SAndrew Jeffery {
171c63f63a2SAndrew Jeffery 	int valid;
172c63f63a2SAndrew Jeffery 
173c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
174c63f63a2SAndrew Jeffery 
175c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
176c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
177c63f63a2SAndrew Jeffery 
178c63f63a2SAndrew Jeffery 	return valid;
179c63f63a2SAndrew Jeffery }
180c63f63a2SAndrew Jeffery 
181c63f63a2SAndrew Jeffery /**
182db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
183db7b8324SAndrew Jeffery  * has been completely consumed without overflow
184db7b8324SAndrew Jeffery  *
185db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
186db7b8324SAndrew Jeffery  *
187db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
188db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
189db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
190db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
191db7b8324SAndrew Jeffery  */
19290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
193cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_destroy_consumed(struct pldm_msgbuf * ctx)19476712f69SAndrew Jeffery pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
195db7b8324SAndrew Jeffery {
196db7b8324SAndrew Jeffery 	int consumed;
197db7b8324SAndrew Jeffery 
198db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
199db7b8324SAndrew Jeffery 
200db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
201db7b8324SAndrew Jeffery 	ctx->remaining = 0;
202db7b8324SAndrew Jeffery 
203db7b8324SAndrew Jeffery 	return consumed;
204db7b8324SAndrew Jeffery }
205db7b8324SAndrew Jeffery 
20666c7723aSAndrew Jeffery /*
20766c7723aSAndrew Jeffery  * Exploit the pre-processor to perform type checking by macro substitution.
20866c7723aSAndrew Jeffery  *
20966c7723aSAndrew Jeffery  * A C type is defined by its alignment as well as its object
21066c7723aSAndrew Jeffery  * size, and compilers have a hammer to enforce it in the form of
21166c7723aSAndrew Jeffery  * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
21266c7723aSAndrew Jeffery  * the libpldm public API this presents a problem: Naively attempting to use the
21366c7723aSAndrew Jeffery  * msgbuf APIs on a member of a packed struct would yield an error.
21466c7723aSAndrew Jeffery  *
21566c7723aSAndrew Jeffery  * The msgbuf APIs are implemented such that data is moved through unaligned
21666c7723aSAndrew Jeffery  * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
21766c7723aSAndrew Jeffery  * make the object pointers take a trip through `void *` at its API boundary.
21866c7723aSAndrew Jeffery  * That presents a bit too much of an opportunity to non-surgically remove your
21966c7723aSAndrew Jeffery  * own foot, so here we set about doing something to mitigate that as well.
22066c7723aSAndrew Jeffery  *
22166c7723aSAndrew Jeffery  * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
22266c7723aSAndrew Jeffery  * only for the purpose of object sizes, disregarding alignment. We have a few
22366c7723aSAndrew Jeffery  * constraints that cause some headaches:
22466c7723aSAndrew Jeffery  *
22566c7723aSAndrew Jeffery  * 1. We have to perform the type-check before a call through a C function,
22666c7723aSAndrew Jeffery  *    as the function must take the object pointer argument as `void *`.
22766c7723aSAndrew Jeffery  *    Essentially, this constrains us to doing something with macros.
22866c7723aSAndrew Jeffery  *
22966c7723aSAndrew Jeffery  * 2. While libpldm is a C library, its test suite is written in C++ to take
23066c7723aSAndrew Jeffery  *    advantage of gtest.
23166c7723aSAndrew Jeffery  *
23266c7723aSAndrew Jeffery  * 3. Ideally we'd do something with C's `static_assert()`, however
23366c7723aSAndrew Jeffery  *    `static_assert()` is defined as void, and as we're constrained to macros,
23466c7723aSAndrew Jeffery  *    using `static_assert()` would require a statement-expression
23566c7723aSAndrew Jeffery  *
23666c7723aSAndrew Jeffery  * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
23766c7723aSAndrew Jeffery  *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
23866c7723aSAndrew Jeffery  *    the purpose of enabling statement-expressions in this one instance.
23966c7723aSAndrew Jeffery  *
24066c7723aSAndrew Jeffery  * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
24166c7723aSAndrew Jeffery  *    however it's implemented in terms of `_Generic()`, which is not available
24266c7723aSAndrew Jeffery  *    in C++.
24366c7723aSAndrew Jeffery  *
24466c7723aSAndrew Jeffery  * Combined this means we need separate solutions for C and C++.
24566c7723aSAndrew Jeffery  *
24666c7723aSAndrew Jeffery  * For C, as we don't have statement-expressions, we need to exploit some other
24766c7723aSAndrew Jeffery  * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
24866c7723aSAndrew Jeffery  * API function call. We also have to take care of the fact that the call-sites
24966c7723aSAndrew Jeffery  * may be in the context of a variable assignment for error-handling purposes.
25066c7723aSAndrew Jeffery  * The key observation is that we can use the comma operator as a sequence point
25166c7723aSAndrew Jeffery  * to order the type check before the API call, discarding the "result" value of
25266c7723aSAndrew Jeffery  * the type check and yielding the return value of the API call.
25366c7723aSAndrew Jeffery  *
25466c7723aSAndrew Jeffery  * C++ could be less of a headache than the C as we can leverage template
25566c7723aSAndrew Jeffery  * functions. An advantage of template functions is that while their definition
25666c7723aSAndrew Jeffery  * is driven by instantion, the definition does not appear at the source
2579e3a5d45SManojkiran Eda  * location of the instantiation, which gives it a great leg-up over the problems
25866c7723aSAndrew Jeffery  * we have in the C path. However, the use of the msgbuf APIs in the test suite
25966c7723aSAndrew Jeffery  * still makes things somewhat tricky, as the call-sites in the test suite are
26066c7723aSAndrew Jeffery  * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
26166c7723aSAndrew Jeffery  * takes both the object type and the required type as template arguments, and
26266c7723aSAndrew Jeffery  * then define the object pointer parameter as `void *` for a call through to
26366c7723aSAndrew Jeffery  * the appropriate msgbuf API. However, because the msgbuf API call-sites are
26466c7723aSAndrew Jeffery  * encapsulated in gtest macros, use of commas in the template specification
26566c7723aSAndrew Jeffery  * causes pre-processor confusion. In this way we're constrained to only one
26666c7723aSAndrew Jeffery  * template argument per function.
26766c7723aSAndrew Jeffery  *
26866c7723aSAndrew Jeffery  * Implement the C++ path using template functions that take the destination
26966c7723aSAndrew Jeffery  * object type as a template argument, while the name of the function symbols
27066c7723aSAndrew Jeffery  * are derived from the required type. The manual implementations of these
27166c7723aSAndrew Jeffery  * appear at the end of the header. The type safety is actually enforced
27266c7723aSAndrew Jeffery  * by `static_assert()` this time, as we can use statements as we're not
27366c7723aSAndrew Jeffery  * constrained to an expression in the templated function body.
27466c7723aSAndrew Jeffery  *
27566c7723aSAndrew Jeffery  * The invocations of pldm_msgbuf_extract_typecheck() typically result in
27666c7723aSAndrew Jeffery  * double-evaluation of some arguments. We're not yet bothered by this for two
27766c7723aSAndrew Jeffery  * reasons:
27866c7723aSAndrew Jeffery  *
27966c7723aSAndrew Jeffery  * 1. The nature of the current call-sites are such that there are no
28066c7723aSAndrew Jeffery  *    argument expressions that result in undesirable side-effects
28166c7723aSAndrew Jeffery  *
28266c7723aSAndrew Jeffery  * 2. It's an API internal to the libpldm implementation, and we can fix things
28366c7723aSAndrew Jeffery  *    whenever something crops up the violates the observation in 1.
28466c7723aSAndrew Jeffery  */
28566c7723aSAndrew Jeffery #ifdef __cplusplus
28666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
28766c7723aSAndrew Jeffery 	pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
28866c7723aSAndrew Jeffery #else
28966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
29066c7723aSAndrew Jeffery 	(pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
29166c7723aSAndrew Jeffery #endif
29266c7723aSAndrew Jeffery 
293db7b8324SAndrew Jeffery /**
294c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
295c63f63a2SAndrew Jeffery  *
2969e3a5d45SManojkiran Eda  * @param[in,out] ctx - pldm_msgbuf context for extractor
297c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
298c63f63a2SAndrew Jeffery  *
299c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
300c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
301c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
302c63f63a2SAndrew Jeffery  */
30366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst)                                    \
30466c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8,     \
305e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
30690bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
307cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
30866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint8(struct pldm_msgbuf * ctx,void * dst)30976712f69SAndrew Jeffery pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
310c63f63a2SAndrew Jeffery {
31190bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
312830c1eb4SAndrew Jeffery 		return -EINVAL;
313c63f63a2SAndrew Jeffery 	}
314c63f63a2SAndrew Jeffery 
3154f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
31666c7723aSAndrew Jeffery 		memcpy(dst, ctx->cursor, sizeof(uint8_t));
317c63f63a2SAndrew Jeffery 		ctx->cursor++;
3184f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(uint8_t);
319c8df31c1SAndrew Jeffery 		return 0;
320c63f63a2SAndrew Jeffery 	}
321c63f63a2SAndrew Jeffery 
3224f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
3234f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(uint8_t);
3244f60fb77SAndrew Jeffery 	}
3254f60fb77SAndrew Jeffery 
3264f60fb77SAndrew Jeffery 	return -EOVERFLOW;
3274f60fb77SAndrew Jeffery }
3284f60fb77SAndrew Jeffery 
32966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst)                                     \
33066c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst,  \
331e5f12538SAndrew Jeffery 				      ctx, (void *)&(dst))
33290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
333cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
33466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int8(struct pldm_msgbuf * ctx,void * dst)33576712f69SAndrew Jeffery pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
336c63f63a2SAndrew Jeffery {
33790bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
338830c1eb4SAndrew Jeffery 		return -EINVAL;
339c63f63a2SAndrew Jeffery 	}
340c63f63a2SAndrew Jeffery 
3414f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
34266c7723aSAndrew Jeffery 		memcpy(dst, ctx->cursor, sizeof(int8_t));
343c63f63a2SAndrew Jeffery 		ctx->cursor++;
3444f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(int8_t);
345c8df31c1SAndrew Jeffery 		return 0;
346c63f63a2SAndrew Jeffery 	}
347c63f63a2SAndrew Jeffery 
3484f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
3494f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(int8_t);
3504f60fb77SAndrew Jeffery 	}
3514f60fb77SAndrew Jeffery 
3524f60fb77SAndrew Jeffery 	return -EOVERFLOW;
3534f60fb77SAndrew Jeffery }
3544f60fb77SAndrew Jeffery 
35566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst)                                   \
35666c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16,   \
357e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
35890bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
359cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
36066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint16(struct pldm_msgbuf * ctx,void * dst)36176712f69SAndrew Jeffery pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
362c63f63a2SAndrew Jeffery {
363c63f63a2SAndrew Jeffery 	uint16_t ldst;
364c63f63a2SAndrew Jeffery 
36590bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
366830c1eb4SAndrew Jeffery 		return -EINVAL;
367c63f63a2SAndrew Jeffery 	}
368c63f63a2SAndrew Jeffery 
3692ff8cf89SAndrew Jeffery 	// Check for underflow while tracking the magnitude of the buffer overflow
3702ff8cf89SAndrew Jeffery 	static_assert(
3712ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
3722ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
3732ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
3742ff8cf89SAndrew Jeffery 
3754f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
376c63f63a2SAndrew Jeffery 		// Use memcpy() to have the compiler deal with any alignment
377c63f63a2SAndrew Jeffery 		// issues on the target architecture
378c63f63a2SAndrew Jeffery 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
379c63f63a2SAndrew Jeffery 
380c63f63a2SAndrew Jeffery 		// Only assign the target value once it's correctly decoded
38166c7723aSAndrew Jeffery 		ldst = le16toh(ldst);
38266c7723aSAndrew Jeffery 
38366c7723aSAndrew Jeffery 		// Allow storing to unaligned
38466c7723aSAndrew Jeffery 		memcpy(dst, &ldst, sizeof(ldst));
38566c7723aSAndrew Jeffery 
386c63f63a2SAndrew Jeffery 		ctx->cursor += sizeof(ldst);
3874f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
388c8df31c1SAndrew Jeffery 		return 0;
389c63f63a2SAndrew Jeffery 	}
390c63f63a2SAndrew Jeffery 
3914f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
3924f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
3934f60fb77SAndrew Jeffery 	}
3944f60fb77SAndrew Jeffery 
3954f60fb77SAndrew Jeffery 	return -EOVERFLOW;
3964f60fb77SAndrew Jeffery }
3974f60fb77SAndrew Jeffery 
39866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst)                                    \
39966c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16,     \
400e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
40190bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
402cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
40366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int16(struct pldm_msgbuf * ctx,void * dst)40476712f69SAndrew Jeffery pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
405c63f63a2SAndrew Jeffery {
406c63f63a2SAndrew Jeffery 	int16_t ldst;
407c63f63a2SAndrew Jeffery 
40890bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
409830c1eb4SAndrew Jeffery 		return -EINVAL;
410c63f63a2SAndrew Jeffery 	}
411c63f63a2SAndrew Jeffery 
4122ff8cf89SAndrew Jeffery 	static_assert(
4132ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4142ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4152ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
416c63f63a2SAndrew Jeffery 
4174f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
418c63f63a2SAndrew Jeffery 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
41966c7723aSAndrew Jeffery 		ldst = le16toh(ldst);
42066c7723aSAndrew Jeffery 		memcpy(dst, &ldst, sizeof(ldst));
421c63f63a2SAndrew Jeffery 		ctx->cursor += sizeof(ldst);
4224f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
423c8df31c1SAndrew Jeffery 		return 0;
424c63f63a2SAndrew Jeffery 	}
425c63f63a2SAndrew Jeffery 
4264f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4274f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
4284f60fb77SAndrew Jeffery 	}
4294f60fb77SAndrew Jeffery 
4304f60fb77SAndrew Jeffery 	return -EOVERFLOW;
4314f60fb77SAndrew Jeffery }
4324f60fb77SAndrew Jeffery 
43366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst)                                   \
43466c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32,   \
435e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
43690bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
437cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
43866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint32(struct pldm_msgbuf * ctx,void * dst)43976712f69SAndrew Jeffery pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
440c63f63a2SAndrew Jeffery {
441c63f63a2SAndrew Jeffery 	uint32_t ldst;
442c63f63a2SAndrew Jeffery 
44390bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
444830c1eb4SAndrew Jeffery 		return -EINVAL;
445c63f63a2SAndrew Jeffery 	}
446c63f63a2SAndrew Jeffery 
4472ff8cf89SAndrew Jeffery 	static_assert(
4482ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4492ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4502ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
451c63f63a2SAndrew Jeffery 
4524f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
453c63f63a2SAndrew Jeffery 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
45466c7723aSAndrew Jeffery 		ldst = le32toh(ldst);
45566c7723aSAndrew Jeffery 		memcpy(dst, &ldst, sizeof(ldst));
456c63f63a2SAndrew Jeffery 		ctx->cursor += sizeof(ldst);
4574f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
458c8df31c1SAndrew Jeffery 		return 0;
459c63f63a2SAndrew Jeffery 	}
460c63f63a2SAndrew Jeffery 
4614f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4624f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
4634f60fb77SAndrew Jeffery 	}
4644f60fb77SAndrew Jeffery 
4654f60fb77SAndrew Jeffery 	return -EOVERFLOW;
4664f60fb77SAndrew Jeffery }
4674f60fb77SAndrew Jeffery 
46866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst)                                    \
46966c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32,     \
470e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
47190bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
472cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
47366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int32(struct pldm_msgbuf * ctx,void * dst)47476712f69SAndrew Jeffery pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
475c63f63a2SAndrew Jeffery {
476c63f63a2SAndrew Jeffery 	int32_t ldst;
477c63f63a2SAndrew Jeffery 
47890bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
479830c1eb4SAndrew Jeffery 		return -EINVAL;
480c63f63a2SAndrew Jeffery 	}
481c63f63a2SAndrew Jeffery 
4822ff8cf89SAndrew Jeffery 	static_assert(
4832ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4842ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4852ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
486c63f63a2SAndrew Jeffery 
4874f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
488c63f63a2SAndrew Jeffery 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
48966c7723aSAndrew Jeffery 		ldst = le32toh(ldst);
49066c7723aSAndrew Jeffery 		memcpy(dst, &ldst, sizeof(ldst));
491c63f63a2SAndrew Jeffery 		ctx->cursor += sizeof(ldst);
4924f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
4934f60fb77SAndrew Jeffery 		return 0;
4944f60fb77SAndrew Jeffery 	}
495c63f63a2SAndrew Jeffery 
4964f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4974f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
4984f60fb77SAndrew Jeffery 	}
4994f60fb77SAndrew Jeffery 
5004f60fb77SAndrew Jeffery 	return -EOVERFLOW;
501c63f63a2SAndrew Jeffery }
502c63f63a2SAndrew Jeffery 
50366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst)                                   \
50466c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32,   \
505e5f12538SAndrew Jeffery 				      dst, ctx, (void *)&(dst))
50690bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
507cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
50866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_real32(struct pldm_msgbuf * ctx,void * dst)50976712f69SAndrew Jeffery pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
510c63f63a2SAndrew Jeffery {
511c63f63a2SAndrew Jeffery 	uint32_t ldst;
512c63f63a2SAndrew Jeffery 
513c8df31c1SAndrew Jeffery 	static_assert(sizeof(real32_t) == sizeof(ldst),
51466c7723aSAndrew Jeffery 		      "Mismatched type sizes for dst and ldst");
51566c7723aSAndrew Jeffery 
51690bbe6c0SAndrew Jeffery 	if (!ctx->cursor) {
517830c1eb4SAndrew Jeffery 		return -EINVAL;
518c63f63a2SAndrew Jeffery 	}
519c63f63a2SAndrew Jeffery 
5202ff8cf89SAndrew Jeffery 	static_assert(
5212ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
5222ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
5232ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
524c63f63a2SAndrew Jeffery 
5254f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
526c63f63a2SAndrew Jeffery 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
527c63f63a2SAndrew Jeffery 		ldst = le32toh(ldst);
52866c7723aSAndrew Jeffery 		memcpy(dst, &ldst, sizeof(ldst));
52966c7723aSAndrew Jeffery 		ctx->cursor += sizeof(ldst);
5304f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
531c8df31c1SAndrew Jeffery 		return 0;
532c63f63a2SAndrew Jeffery 	}
533c63f63a2SAndrew Jeffery 
5344f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
5354f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(ldst);
5364f60fb77SAndrew Jeffery 	}
5374f60fb77SAndrew Jeffery 
5384f60fb77SAndrew Jeffery 	return -EOVERFLOW;
5394f60fb77SAndrew Jeffery }
5404f60fb77SAndrew Jeffery 
54166c7723aSAndrew Jeffery /**
54266c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the lvalue named by dst.
54366c7723aSAndrew Jeffery  *
54466c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
54566c7723aSAndrew Jeffery  * @param dst The lvalue into which the field at the msgbuf cursor should be
54666c7723aSAndrew Jeffery  *            extracted
54766c7723aSAndrew Jeffery  *
54866c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
54966c7723aSAndrew Jeffery  */
550c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
55166c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
55266c7723aSAndrew Jeffery 		uint8_t: pldm__msgbuf_extract_uint8,                           \
55366c7723aSAndrew Jeffery 		int8_t: pldm__msgbuf_extract_int8,                             \
55466c7723aSAndrew Jeffery 		uint16_t: pldm__msgbuf_extract_uint16,                         \
55566c7723aSAndrew Jeffery 		int16_t: pldm__msgbuf_extract_int16,                           \
55666c7723aSAndrew Jeffery 		uint32_t: pldm__msgbuf_extract_uint32,                         \
55766c7723aSAndrew Jeffery 		int32_t: pldm__msgbuf_extract_int32,                           \
55866c7723aSAndrew Jeffery 		real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
55966c7723aSAndrew Jeffery 
56066c7723aSAndrew Jeffery /**
56166c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the object pointed-to by dst.
56266c7723aSAndrew Jeffery  *
56366c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
56466c7723aSAndrew Jeffery  * @param dst The pointer to the object into which the field at the msgbuf
56566c7723aSAndrew Jeffery  *            cursor should be extracted
56666c7723aSAndrew Jeffery  *
56766c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
56866c7723aSAndrew Jeffery  */
56966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst)                                        \
57066c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
57166c7723aSAndrew Jeffery 		uint8_t *: pldm__msgbuf_extract_uint8,                         \
57266c7723aSAndrew Jeffery 		int8_t *: pldm__msgbuf_extract_int8,                           \
57366c7723aSAndrew Jeffery 		uint16_t *: pldm__msgbuf_extract_uint16,                       \
57466c7723aSAndrew Jeffery 		int16_t *: pldm__msgbuf_extract_int16,                         \
57566c7723aSAndrew Jeffery 		uint32_t *: pldm__msgbuf_extract_uint32,                       \
57666c7723aSAndrew Jeffery 		int32_t *: pldm__msgbuf_extract_int32,                         \
57766c7723aSAndrew Jeffery 		real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
578c63f63a2SAndrew Jeffery 
5790a1be3cbSAndrew Jeffery /**
5800a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_extract_array
5810a1be3cbSAndrew Jeffery  */
58290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
5830a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
584cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
5851c57144dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_array_void(struct pldm_msgbuf * ctx,size_t count,void * dst,size_t dst_count)5860a1be3cbSAndrew Jeffery pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
5870a1be3cbSAndrew Jeffery 				void *dst, size_t dst_count)
588369b121aSAndrew Jeffery {
58990bbe6c0SAndrew Jeffery 	if (!ctx->cursor || count > dst_count) {
590830c1eb4SAndrew Jeffery 		return -EINVAL;
591369b121aSAndrew Jeffery 	}
592369b121aSAndrew Jeffery 
593369b121aSAndrew Jeffery 	if (!count) {
594c8df31c1SAndrew Jeffery 		return 0;
595369b121aSAndrew Jeffery 	}
596369b121aSAndrew Jeffery 
5972ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
5982ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
599830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
600369b121aSAndrew Jeffery 	}
6012ff8cf89SAndrew Jeffery #endif
602369b121aSAndrew Jeffery 
6034f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)count) {
604a065eccbSAndrew Jeffery 		memcpy(dst, ctx->cursor, count);
605a065eccbSAndrew Jeffery 		ctx->cursor += count;
6064f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)count;
607c8df31c1SAndrew Jeffery 		return 0;
608369b121aSAndrew Jeffery 	}
609369b121aSAndrew Jeffery 
6104f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
6114f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)count;
6124f60fb77SAndrew Jeffery 	}
6134f60fb77SAndrew Jeffery 
6144f60fb77SAndrew Jeffery 	return -EOVERFLOW;
6154f60fb77SAndrew Jeffery }
6164f60fb77SAndrew Jeffery 
6170a1be3cbSAndrew Jeffery /**
6180a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_extract_array
6190a1be3cbSAndrew Jeffery  */
62090bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
6210a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
622cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_extract_array_char(struct pldm_msgbuf * ctx,size_t count,char * dst,size_t dst_count)6230a1be3cbSAndrew Jeffery pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
6240a1be3cbSAndrew Jeffery 			       size_t dst_count)
6251c57144dSAndrew Jeffery {
6260a1be3cbSAndrew Jeffery 	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
6271c57144dSAndrew Jeffery }
6281c57144dSAndrew Jeffery 
6290a1be3cbSAndrew Jeffery /**
6300a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_extract_array
6310a1be3cbSAndrew Jeffery  */
63290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
6330a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
634cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf * ctx,size_t count,uint8_t * dst,size_t dst_count)6350a1be3cbSAndrew Jeffery pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
6360a1be3cbSAndrew Jeffery 				uint8_t *dst, size_t dst_count)
6371c57144dSAndrew Jeffery {
6380a1be3cbSAndrew Jeffery 	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
6391c57144dSAndrew Jeffery }
6401c57144dSAndrew Jeffery 
6410a1be3cbSAndrew Jeffery /**
6420a1be3cbSAndrew Jeffery  * Extract an array of data from the msgbuf instance
6430a1be3cbSAndrew Jeffery  *
6440a1be3cbSAndrew Jeffery  * @param ctx - The msgbuf instance from which to extract an array of data
6450a1be3cbSAndrew Jeffery  * @param count - The number of array elements to extract
6460a1be3cbSAndrew Jeffery  * @param dst - The array object into which elements from @p ctx should be
6470a1be3cbSAndrew Jeffery                 extracted
6480a1be3cbSAndrew Jeffery  * @param dst_count - The maximum number of elements to place into @p dst
6490a1be3cbSAndrew Jeffery  *
6500a1be3cbSAndrew Jeffery  * Note that both @p count and @p dst_count can only be counted by `sizeof` for
6510a1be3cbSAndrew Jeffery  * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
6520a1be3cbSAndrew Jeffery  * of array elements and _not_ the object size of the array.
6530a1be3cbSAndrew Jeffery  */
6540a1be3cbSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, count, dst, dst_count)                  \
6551c57144dSAndrew Jeffery 	_Generic((*(dst)),                                                     \
6561c57144dSAndrew Jeffery 		uint8_t: pldm_msgbuf_extract_array_uint8,                      \
6570a1be3cbSAndrew Jeffery 		char: pldm_msgbuf_extract_array_char)(ctx, count, dst,         \
6580a1be3cbSAndrew Jeffery 						      dst_count)
659369b121aSAndrew Jeffery 
66090bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_uint64(struct pldm_msgbuf * ctx,const uint64_t src)661e8d8d338SMatt Johnston LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint64(struct pldm_msgbuf *ctx,
662e8d8d338SMatt Johnston 						       const uint64_t src)
663e8d8d338SMatt Johnston {
664e8d8d338SMatt Johnston 	uint64_t val = htole64(src);
665e8d8d338SMatt Johnston 
666e8d8d338SMatt Johnston 	if (!ctx->cursor) {
667e8d8d338SMatt Johnston 		return -EINVAL;
668e8d8d338SMatt Johnston 	}
669e8d8d338SMatt Johnston 
670e8d8d338SMatt Johnston 	static_assert(
671e8d8d338SMatt Johnston 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
672e8d8d338SMatt Johnston 		sizeof(src) < INTMAX_MAX,
673e8d8d338SMatt Johnston 		"The following addition may not uphold the runtime assertion");
674e8d8d338SMatt Johnston 
675e8d8d338SMatt Johnston 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
676e8d8d338SMatt Johnston 		memcpy(ctx->cursor, &val, sizeof(val));
677e8d8d338SMatt Johnston 		ctx->cursor += sizeof(src);
678e8d8d338SMatt Johnston 		ctx->remaining -= sizeof(src);
679e8d8d338SMatt Johnston 		return 0;
680e8d8d338SMatt Johnston 	}
681e8d8d338SMatt Johnston 
682e8d8d338SMatt Johnston 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
683e8d8d338SMatt Johnston 		ctx->remaining -= sizeof(src);
684e8d8d338SMatt Johnston 	}
685e8d8d338SMatt Johnston 
686e8d8d338SMatt Johnston 	return -EOVERFLOW;
687e8d8d338SMatt Johnston }
688e8d8d338SMatt Johnston 
689e8d8d338SMatt Johnston LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_uint32(struct pldm_msgbuf * ctx,const uint32_t src)690cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
691cb569bc5SAndrew Jeffery 						       const uint32_t src)
692062c8762SThu Nguyen {
693062c8762SThu Nguyen 	uint32_t val = htole32(src);
694062c8762SThu Nguyen 
695c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
696830c1eb4SAndrew Jeffery 		return -EINVAL;
697062c8762SThu Nguyen 	}
698062c8762SThu Nguyen 
6992ff8cf89SAndrew Jeffery 	static_assert(
7002ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7012ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7022ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
703062c8762SThu Nguyen 
7044f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
705062c8762SThu Nguyen 		memcpy(ctx->cursor, &val, sizeof(val));
706062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
7074f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
708c8df31c1SAndrew Jeffery 		return 0;
709062c8762SThu Nguyen 	}
710062c8762SThu Nguyen 
7114f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
7124f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
7134f60fb77SAndrew Jeffery 	}
7144f60fb77SAndrew Jeffery 
7154f60fb77SAndrew Jeffery 	return -EOVERFLOW;
7164f60fb77SAndrew Jeffery }
7174f60fb77SAndrew Jeffery 
71890bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_uint16(struct pldm_msgbuf * ctx,const uint16_t src)719cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
720cb569bc5SAndrew Jeffery 						       const uint16_t src)
721062c8762SThu Nguyen {
722062c8762SThu Nguyen 	uint16_t val = htole16(src);
723062c8762SThu Nguyen 
724c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
725830c1eb4SAndrew Jeffery 		return -EINVAL;
726062c8762SThu Nguyen 	}
727062c8762SThu Nguyen 
7282ff8cf89SAndrew Jeffery 	static_assert(
7292ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7302ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7312ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
732062c8762SThu Nguyen 
7334f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
734062c8762SThu Nguyen 		memcpy(ctx->cursor, &val, sizeof(val));
735062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
7364f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
737c8df31c1SAndrew Jeffery 		return 0;
738062c8762SThu Nguyen 	}
739062c8762SThu Nguyen 
7404f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
7414f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
7424f60fb77SAndrew Jeffery 	}
7434f60fb77SAndrew Jeffery 
7444f60fb77SAndrew Jeffery 	return -EOVERFLOW;
7454f60fb77SAndrew Jeffery }
7464f60fb77SAndrew Jeffery 
74790bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_uint8(struct pldm_msgbuf * ctx,const uint8_t src)748cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
749cb569bc5SAndrew Jeffery 						      const uint8_t src)
750062c8762SThu Nguyen {
751c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
752830c1eb4SAndrew Jeffery 		return -EINVAL;
753062c8762SThu Nguyen 	}
754062c8762SThu Nguyen 
7552ff8cf89SAndrew Jeffery 	static_assert(
7562ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7572ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7582ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
759062c8762SThu Nguyen 
7604f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
761062c8762SThu Nguyen 		memcpy(ctx->cursor, &src, sizeof(src));
762062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
7634f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
764c8df31c1SAndrew Jeffery 		return 0;
765062c8762SThu Nguyen 	}
766062c8762SThu Nguyen 
7674f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
7684f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
7694f60fb77SAndrew Jeffery 	}
7704f60fb77SAndrew Jeffery 
7714f60fb77SAndrew Jeffery 	return -EOVERFLOW;
7724f60fb77SAndrew Jeffery }
7734f60fb77SAndrew Jeffery 
77490bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_int32(struct pldm_msgbuf * ctx,const int32_t src)775cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
776cb569bc5SAndrew Jeffery 						      const int32_t src)
777062c8762SThu Nguyen {
778062c8762SThu Nguyen 	int32_t val = htole32(src);
779062c8762SThu Nguyen 
780c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
781830c1eb4SAndrew Jeffery 		return -EINVAL;
782062c8762SThu Nguyen 	}
783062c8762SThu Nguyen 
7842ff8cf89SAndrew Jeffery 	static_assert(
7852ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7862ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7872ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
788062c8762SThu Nguyen 
7894f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
790062c8762SThu Nguyen 		memcpy(ctx->cursor, &val, sizeof(val));
791062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
7924f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
793c8df31c1SAndrew Jeffery 		return 0;
794062c8762SThu Nguyen 	}
795062c8762SThu Nguyen 
7964f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
7974f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
7984f60fb77SAndrew Jeffery 	}
7994f60fb77SAndrew Jeffery 
8004f60fb77SAndrew Jeffery 	return -EOVERFLOW;
8014f60fb77SAndrew Jeffery }
8024f60fb77SAndrew Jeffery 
80390bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_int16(struct pldm_msgbuf * ctx,const int16_t src)804cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
805cb569bc5SAndrew Jeffery 						      const int16_t src)
806062c8762SThu Nguyen {
807062c8762SThu Nguyen 	int16_t val = htole16(src);
808062c8762SThu Nguyen 
809c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
810830c1eb4SAndrew Jeffery 		return -EINVAL;
811062c8762SThu Nguyen 	}
812062c8762SThu Nguyen 
8132ff8cf89SAndrew Jeffery 	static_assert(
8142ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
8152ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
8162ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
817062c8762SThu Nguyen 
8184f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
819062c8762SThu Nguyen 		memcpy(ctx->cursor, &val, sizeof(val));
820062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
8214f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
822c8df31c1SAndrew Jeffery 		return 0;
823062c8762SThu Nguyen 	}
824062c8762SThu Nguyen 
8254f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
8264f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
8274f60fb77SAndrew Jeffery 	}
8284f60fb77SAndrew Jeffery 
8294f60fb77SAndrew Jeffery 	return -EOVERFLOW;
8304f60fb77SAndrew Jeffery }
8314f60fb77SAndrew Jeffery 
83290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_int8(struct pldm_msgbuf * ctx,const int8_t src)833cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
834cb569bc5SAndrew Jeffery 						     const int8_t src)
835062c8762SThu Nguyen {
836c8df31c1SAndrew Jeffery 	if (!ctx->cursor) {
837830c1eb4SAndrew Jeffery 		return -EINVAL;
838062c8762SThu Nguyen 	}
839062c8762SThu Nguyen 
8402ff8cf89SAndrew Jeffery 	static_assert(
8412ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
8422ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
8432ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
844062c8762SThu Nguyen 
8454f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
846062c8762SThu Nguyen 		memcpy(ctx->cursor, &src, sizeof(src));
847062c8762SThu Nguyen 		ctx->cursor += sizeof(src);
8484f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
849c8df31c1SAndrew Jeffery 		return 0;
850062c8762SThu Nguyen 	}
851062c8762SThu Nguyen 
8524f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
8534f60fb77SAndrew Jeffery 		ctx->remaining -= sizeof(src);
8544f60fb77SAndrew Jeffery 	}
8554f60fb77SAndrew Jeffery 
8564f60fb77SAndrew Jeffery 	return -EOVERFLOW;
8574f60fb77SAndrew Jeffery }
8584f60fb77SAndrew Jeffery 
859062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
86037dd6a3dSAndrew Jeffery 	_Generic((src),                                                        \
86137dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_uint8,                             \
86237dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_insert_int8,                               \
86337dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_insert_uint16,                           \
86437dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_insert_int16,                             \
86537dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_insert_uint32,                           \
866e8d8d338SMatt Johnston 		int32_t: pldm_msgbuf_insert_int32,                             \
867e8d8d338SMatt Johnston 		uint64_t: pldm_msgbuf_insert_uint64)(dst, src)
868062c8762SThu Nguyen 
8690a1be3cbSAndrew Jeffery /**
8700a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_insert_array
8710a1be3cbSAndrew Jeffery  */
87290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
8730a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
874cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
8751c57144dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_insert_array_void(struct pldm_msgbuf * ctx,size_t count,const void * src,size_t src_count)8760a1be3cbSAndrew Jeffery pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
8770a1be3cbSAndrew Jeffery 			       const void *src, size_t src_count)
878062c8762SThu Nguyen {
87990bbe6c0SAndrew Jeffery 	if (!ctx->cursor || count > src_count) {
880830c1eb4SAndrew Jeffery 		return -EINVAL;
881062c8762SThu Nguyen 	}
882062c8762SThu Nguyen 
883062c8762SThu Nguyen 	if (!count) {
884c8df31c1SAndrew Jeffery 		return 0;
885062c8762SThu Nguyen 	}
886062c8762SThu Nguyen 
8872ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
8882ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
889830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
890062c8762SThu Nguyen 	}
8912ff8cf89SAndrew Jeffery #endif
892062c8762SThu Nguyen 
8934f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)count) {
894a065eccbSAndrew Jeffery 		memcpy(ctx->cursor, src, count);
895a065eccbSAndrew Jeffery 		ctx->cursor += count;
8964f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)count;
897c8df31c1SAndrew Jeffery 		return 0;
898062c8762SThu Nguyen 	}
899062c8762SThu Nguyen 
9004f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
9014f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)count;
9024f60fb77SAndrew Jeffery 	}
9034f60fb77SAndrew Jeffery 
9044f60fb77SAndrew Jeffery 	return -EOVERFLOW;
9054f60fb77SAndrew Jeffery }
9064f60fb77SAndrew Jeffery 
9070a1be3cbSAndrew Jeffery /**
9080a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_insert_array
9090a1be3cbSAndrew Jeffery  */
91090bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
9110a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
912cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_array_char(struct pldm_msgbuf * ctx,size_t count,const char * src,size_t src_count)9130a1be3cbSAndrew Jeffery pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
9140a1be3cbSAndrew Jeffery 			      const char *src, size_t src_count)
9151c57144dSAndrew Jeffery {
9160a1be3cbSAndrew Jeffery 	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
9171c57144dSAndrew Jeffery }
9181c57144dSAndrew Jeffery 
9190a1be3cbSAndrew Jeffery /**
9200a1be3cbSAndrew Jeffery  * @ref pldm_msgbuf_insert_array
9210a1be3cbSAndrew Jeffery  */
92290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
9230a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
924cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf * ctx,size_t count,const uint8_t * src,size_t src_count)9250a1be3cbSAndrew Jeffery pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
9260a1be3cbSAndrew Jeffery 			       const uint8_t *src, size_t src_count)
9271c57144dSAndrew Jeffery {
9280a1be3cbSAndrew Jeffery 	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
9291c57144dSAndrew Jeffery }
9301c57144dSAndrew Jeffery 
9310a1be3cbSAndrew Jeffery /**
9320a1be3cbSAndrew Jeffery  * Insert an array of data into the msgbuf instance
9330a1be3cbSAndrew Jeffery  *
9340a1be3cbSAndrew Jeffery  * @param ctx - The msgbuf instance into which the array of data should be
9350a1be3cbSAndrew Jeffery  *              inserted
9360a1be3cbSAndrew Jeffery  * @param count - The number of array elements to insert
9370a1be3cbSAndrew Jeffery  * @param src - The array object from which elements should be inserted into
9380a1be3cbSAndrew Jeffery                 @p ctx
9390a1be3cbSAndrew Jeffery  * @param src_count - The maximum number of elements to insert from @p src
9400a1be3cbSAndrew Jeffery  *
9410a1be3cbSAndrew Jeffery  * Note that both @p count and @p src_count can only be counted by `sizeof` for
9420a1be3cbSAndrew Jeffery  * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
9430a1be3cbSAndrew Jeffery  * of array elements and _not_ the object size of the array.
9440a1be3cbSAndrew Jeffery  */
9450a1be3cbSAndrew Jeffery #define pldm_msgbuf_insert_array(dst, count, src, src_count)                   \
9461c57144dSAndrew Jeffery 	_Generic((*(src)),                                                     \
9471c57144dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_array_uint8,                       \
9480a1be3cbSAndrew Jeffery 		char: pldm_msgbuf_insert_array_char)(dst, count, src,          \
9490a1be3cbSAndrew Jeffery 						     src_count)
950062c8762SThu Nguyen 
9517939382fSVarsha Kaverappa LIBPLDM_CC_NONNULL_ARGS(1)
pldm_msgbuf_span_required(struct pldm_msgbuf * ctx,size_t required,void ** cursor)952cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
953cb569bc5SAndrew Jeffery 						       size_t required,
95476712f69SAndrew Jeffery 						       void **cursor)
955062c8762SThu Nguyen {
9567939382fSVarsha Kaverappa 	if (!ctx->cursor || (cursor && *cursor)) {
957830c1eb4SAndrew Jeffery 		return -EINVAL;
958062c8762SThu Nguyen 	}
959062c8762SThu Nguyen 
9602ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
9612ff8cf89SAndrew Jeffery 	if (required > INTMAX_MAX) {
962830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
963062c8762SThu Nguyen 	}
9642ff8cf89SAndrew Jeffery #endif
965062c8762SThu Nguyen 
9664f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)required) {
9677939382fSVarsha Kaverappa 		if (cursor) {
968062c8762SThu Nguyen 			*cursor = ctx->cursor;
9697939382fSVarsha Kaverappa 		}
970062c8762SThu Nguyen 		ctx->cursor += required;
9714f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)required;
972c8df31c1SAndrew Jeffery 		return 0;
973062c8762SThu Nguyen 	}
974062c8762SThu Nguyen 
9754f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)required) {
9764f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)required;
9774f60fb77SAndrew Jeffery 	}
9784f60fb77SAndrew Jeffery 
9794f60fb77SAndrew Jeffery 	return -EOVERFLOW;
9804f60fb77SAndrew Jeffery }
9814f60fb77SAndrew Jeffery 
98290bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL_ARGS(1)
983cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_span_string_ascii(struct pldm_msgbuf * ctx,void ** cursor,size_t * length)9849c83d681SThu Nguyen pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
9859c83d681SThu Nguyen 			      size_t *length)
9869c83d681SThu Nguyen {
9879c83d681SThu Nguyen 	intmax_t measured;
9889c83d681SThu Nguyen 
9899c83d681SThu Nguyen 	if (!ctx->cursor || (cursor && *cursor)) {
990830c1eb4SAndrew Jeffery 		return -EINVAL;
9919c83d681SThu Nguyen 	}
9929c83d681SThu Nguyen 
9939c83d681SThu Nguyen 	if (ctx->remaining < 0) {
9949c83d681SThu Nguyen 		/* Tracking the amount of overflow gets disturbed here */
995830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
9969c83d681SThu Nguyen 	}
9979c83d681SThu Nguyen 
9989c83d681SThu Nguyen 	measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
9999c83d681SThu Nguyen 	if (measured == ctx->remaining) {
10009c83d681SThu Nguyen 		/*
10019c83d681SThu Nguyen 		 * We have hit the end of the buffer prior to the NUL terminator.
10029c83d681SThu Nguyen 		 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
10039c83d681SThu Nguyen 		 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
10049c83d681SThu Nguyen 		 * return an error.
10059c83d681SThu Nguyen 		 */
10069c83d681SThu Nguyen 		ctx->remaining = -1;
1007830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
10089c83d681SThu Nguyen 	}
10099c83d681SThu Nguyen 
10109c83d681SThu Nguyen 	/* Include the NUL terminator in the span length, as spans are opaque */
10119c83d681SThu Nguyen 	measured++;
10129c83d681SThu Nguyen 
10134f60fb77SAndrew Jeffery 	if (ctx->remaining >= measured) {
10149c83d681SThu Nguyen 		if (cursor) {
10159c83d681SThu Nguyen 			*cursor = ctx->cursor;
10169c83d681SThu Nguyen 		}
10179c83d681SThu Nguyen 
10189c83d681SThu Nguyen 		ctx->cursor += measured;
10199c83d681SThu Nguyen 
10209c83d681SThu Nguyen 		if (length) {
10219c83d681SThu Nguyen 			*length = measured;
10229c83d681SThu Nguyen 		}
10239c83d681SThu Nguyen 
10244f60fb77SAndrew Jeffery 		ctx->remaining -= measured;
10259c83d681SThu Nguyen 		return 0;
10269c83d681SThu Nguyen 	}
10279c83d681SThu Nguyen 
10284f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + measured) {
10294f60fb77SAndrew Jeffery 		ctx->remaining -= measured;
10304f60fb77SAndrew Jeffery 	}
10314f60fb77SAndrew Jeffery 
10324f60fb77SAndrew Jeffery 	return -EOVERFLOW;
10334f60fb77SAndrew Jeffery }
10344f60fb77SAndrew Jeffery 
103590bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL_ARGS(1)
1036cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_span_string_utf16(struct pldm_msgbuf * ctx,void ** cursor,size_t * length)10371523778dSThu Nguyen pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
10381523778dSThu Nguyen 			      size_t *length)
10391523778dSThu Nguyen {
10401523778dSThu Nguyen 	static const char16_t term = 0;
10411523778dSThu Nguyen 	ptrdiff_t measured;
10421523778dSThu Nguyen 	void *end;
10431523778dSThu Nguyen 
10441523778dSThu Nguyen 	if (!ctx->cursor || (cursor && *cursor)) {
1045830c1eb4SAndrew Jeffery 		return -EINVAL;
10461523778dSThu Nguyen 	}
10471523778dSThu Nguyen 
10481523778dSThu Nguyen 	if (ctx->remaining < 0) {
10491523778dSThu Nguyen 		/* Tracking the amount of overflow gets disturbed here */
1050830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
10511523778dSThu Nguyen 	}
10521523778dSThu Nguyen 
10531523778dSThu Nguyen 	/*
10541523778dSThu Nguyen 	 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
10551523778dSThu Nguyen 	 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
10561523778dSThu Nguyen 	 * start of the string
10571523778dSThu Nguyen 	 */
10582b440d4cSAndrew Jeffery 	end = ctx->cursor;
10591523778dSThu Nguyen 	do {
10601523778dSThu Nguyen 		if (end != ctx->cursor) {
10611523778dSThu Nguyen 			/*
10621523778dSThu Nguyen 			 * If we've looped we've found a relatively-unaligned NUL code-point.
10631523778dSThu Nguyen 			 * Scan again from a relatively-aligned start point.
10641523778dSThu Nguyen 			 */
10651523778dSThu Nguyen 			end = (char *)end + 1;
10661523778dSThu Nguyen 		}
10671523778dSThu Nguyen 		measured = (char *)end - (char *)ctx->cursor;
10682b440d4cSAndrew Jeffery 		end = memmem(end, ctx->remaining - measured, &term,
10691523778dSThu Nguyen 			     sizeof(term));
10701523778dSThu Nguyen 	} while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
10711523778dSThu Nguyen 
10721523778dSThu Nguyen 	if (!end) {
10731523778dSThu Nguyen 		/*
10741523778dSThu Nguyen 		 * Optimistically, the last required pattern byte was one beyond the end of
10751523778dSThu Nguyen 		 * the buffer. Setting ctx->remaining negative ensures the
10761523778dSThu Nguyen 		 * `pldm_msgbuf_destroy*()` APIs also return an error.
10771523778dSThu Nguyen 		 */
10781523778dSThu Nguyen 		ctx->remaining = -1;
1079830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
10801523778dSThu Nguyen 	}
10811523778dSThu Nguyen 
10821523778dSThu Nguyen 	end = (char *)end + sizeof(char16_t);
10831523778dSThu Nguyen 	measured = (char *)end - (char *)ctx->cursor;
10841523778dSThu Nguyen 
10851523778dSThu Nguyen #if INTMAX_MAX < PTRDIFF_MAX
10861523778dSThu Nguyen 	if (measured >= INTMAX_MAX) {
10871523778dSThu Nguyen 		return pldm_msgbuf_status(ctx, EOVERFLOW);
10881523778dSThu Nguyen 	}
10891523778dSThu Nguyen #endif
10901523778dSThu Nguyen 
10914f60fb77SAndrew Jeffery 	if (ctx->remaining >= (intmax_t)measured) {
10921523778dSThu Nguyen 		if (cursor) {
10931523778dSThu Nguyen 			*cursor = ctx->cursor;
10941523778dSThu Nguyen 		}
10951523778dSThu Nguyen 
10961523778dSThu Nguyen 		ctx->cursor += measured;
10971523778dSThu Nguyen 
10981523778dSThu Nguyen 		if (length) {
10991523778dSThu Nguyen 			*length = (size_t)measured;
11001523778dSThu Nguyen 		}
11011523778dSThu Nguyen 
11024f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)measured;
11031523778dSThu Nguyen 		return 0;
11041523778dSThu Nguyen 	}
11051523778dSThu Nguyen 
11064f60fb77SAndrew Jeffery 	if (ctx->remaining >= INTMAX_MIN + (intmax_t)measured) {
11074f60fb77SAndrew Jeffery 		ctx->remaining -= (intmax_t)measured;
11084f60fb77SAndrew Jeffery 	}
11094f60fb77SAndrew Jeffery 
11104f60fb77SAndrew Jeffery 	return -EOVERFLOW;
11114f60fb77SAndrew Jeffery }
11124f60fb77SAndrew Jeffery 
111390bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
1114cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_span_remaining(struct pldm_msgbuf * ctx,void ** cursor,size_t * len)111576712f69SAndrew Jeffery pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
1116062c8762SThu Nguyen {
111790bbe6c0SAndrew Jeffery 	if (!ctx->cursor || *cursor) {
1118830c1eb4SAndrew Jeffery 		return -EINVAL;
1119062c8762SThu Nguyen 	}
1120062c8762SThu Nguyen 
1121062c8762SThu Nguyen 	if (ctx->remaining < 0) {
1122830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
1123062c8762SThu Nguyen 	}
1124062c8762SThu Nguyen 
1125062c8762SThu Nguyen 	*cursor = ctx->cursor;
1126062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
1127062c8762SThu Nguyen 	*len = ctx->remaining;
1128062c8762SThu Nguyen 	ctx->remaining = 0;
1129062c8762SThu Nguyen 
1130c8df31c1SAndrew Jeffery 	return 0;
1131062c8762SThu Nguyen }
1132909bf7c2SVarsha Kaverappa 
1133*8f3b13c4SMatt Johnston LIBPLDM_CC_NONNULL
1134*8f3b13c4SMatt Johnston LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_peek_remaining(struct pldm_msgbuf * ctx,void ** cursor,size_t * len)1135*8f3b13c4SMatt Johnston pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
1136*8f3b13c4SMatt Johnston {
1137*8f3b13c4SMatt Johnston 	if (!ctx->cursor || *cursor) {
1138*8f3b13c4SMatt Johnston 		return -EINVAL;
1139*8f3b13c4SMatt Johnston 	}
1140*8f3b13c4SMatt Johnston 
1141*8f3b13c4SMatt Johnston 	if (ctx->remaining < 0) {
1142*8f3b13c4SMatt Johnston 		return -EOVERFLOW;
1143*8f3b13c4SMatt Johnston 	}
1144*8f3b13c4SMatt Johnston 
1145*8f3b13c4SMatt Johnston 	*cursor = ctx->cursor;
1146*8f3b13c4SMatt Johnston 	*len = ctx->remaining;
1147*8f3b13c4SMatt Johnston 
1148*8f3b13c4SMatt Johnston 	return 0;
1149*8f3b13c4SMatt Johnston }
1150*8f3b13c4SMatt Johnston 
1151*8f3b13c4SMatt Johnston LIBPLDM_CC_NONNULL
pldm_msgbuf_skip(struct pldm_msgbuf * ctx,size_t count)1152*8f3b13c4SMatt Johnston LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf *ctx,
1153*8f3b13c4SMatt Johnston 					      size_t count)
1154*8f3b13c4SMatt Johnston {
1155*8f3b13c4SMatt Johnston 	if (!ctx->cursor) {
1156*8f3b13c4SMatt Johnston 		return -EINVAL;
1157*8f3b13c4SMatt Johnston 	}
1158*8f3b13c4SMatt Johnston 
1159*8f3b13c4SMatt Johnston #if INTMAX_MAX < SIZE_MAX
1160*8f3b13c4SMatt Johnston 	if (count > INTMAX_MAX) {
1161*8f3b13c4SMatt Johnston 		return -EOVERFLOW;
1162*8f3b13c4SMatt Johnston 	}
1163*8f3b13c4SMatt Johnston #endif
1164*8f3b13c4SMatt Johnston 
1165*8f3b13c4SMatt Johnston 	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
1166*8f3b13c4SMatt Johnston 		return -EOVERFLOW;
1167*8f3b13c4SMatt Johnston 	}
1168*8f3b13c4SMatt Johnston 	ctx->remaining -= (intmax_t)count;
1169*8f3b13c4SMatt Johnston 	if (ctx->remaining < 0) {
1170*8f3b13c4SMatt Johnston 		return -EOVERFLOW;
1171*8f3b13c4SMatt Johnston 	}
1172*8f3b13c4SMatt Johnston 	ctx->cursor += count;
1173*8f3b13c4SMatt Johnston 
1174*8f3b13c4SMatt Johnston 	return 0;
1175*8f3b13c4SMatt Johnston }
1176*8f3b13c4SMatt Johnston 
1177909bf7c2SVarsha Kaverappa /**
11785d4f7b57SMatt Johnston  * Return the number of bytes used in a msgbuf instance.
11795d4f7b57SMatt Johnston  *
11805d4f7b57SMatt Johnston  * @param ctx - The msgbuf.
11815d4f7b57SMatt Johnston  * @param orig_len - The original size of the msgbuf, the `len` argument passed to
11825d4f7b57SMatt Johnston  * 		pldm_msgbuf_init_errno().
11835d4f7b57SMatt Johnston  * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
11845d4f7b57SMatt Johnston  *
11855d4f7b57SMatt Johnston  * This can be called after a number of pldm_msgbuf_insert...() calls to
11865d4f7b57SMatt Johnston  * determine the total size that was written.
11875d4f7b57SMatt Johnston  *
11885d4f7b57SMatt Johnston  */
11895d4f7b57SMatt Johnston LIBPLDM_CC_NONNULL
pldm_msgbuf_destroy_used(struct pldm_msgbuf * ctx,size_t orig_len,size_t * ret_used_len)11905d4f7b57SMatt Johnston LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy_used(struct pldm_msgbuf *ctx,
11915d4f7b57SMatt Johnston 						      size_t orig_len,
11925d4f7b57SMatt Johnston 						      size_t *ret_used_len)
11935d4f7b57SMatt Johnston {
11945d4f7b57SMatt Johnston 	int rc;
11955d4f7b57SMatt Johnston 	rc = pldm_msgbuf_validate(ctx);
11965d4f7b57SMatt Johnston 	if (rc) {
11975d4f7b57SMatt Johnston 		return rc;
11985d4f7b57SMatt Johnston 	}
11995d4f7b57SMatt Johnston 
12005d4f7b57SMatt Johnston 	if ((size_t)ctx->remaining > orig_len) {
12015d4f7b57SMatt Johnston 		/* Caller passed incorrect orig_len */
12025d4f7b57SMatt Johnston 		return -EOVERFLOW;
12035d4f7b57SMatt Johnston 	}
12045d4f7b57SMatt Johnston 
12055d4f7b57SMatt Johnston 	*ret_used_len = orig_len - ctx->remaining;
12065d4f7b57SMatt Johnston 	return 0;
12075d4f7b57SMatt Johnston }
12085d4f7b57SMatt Johnston 
12095d4f7b57SMatt Johnston /**
1210909bf7c2SVarsha Kaverappa  * @brief pldm_msgbuf copy data between two msg buffers
1211909bf7c2SVarsha Kaverappa  *
12129e3a5d45SManojkiran Eda  * @param[in,out] src - pldm_msgbuf for source from where value should be copied
12139e3a5d45SManojkiran Eda  * @param[in,out] dst - destination of copy from source
1214909bf7c2SVarsha Kaverappa  * @param[in] size - size of data to be copied
1215909bf7c2SVarsha Kaverappa  * @param[in] description - description of data copied
1216909bf7c2SVarsha Kaverappa  *
1217909bf7c2SVarsha Kaverappa  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1218909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_LENGTH otherwise.
1219909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_DATA if input is invalid
1220909bf7c2SVarsha Kaverappa  */
1221909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name)                                 \
1222909bf7c2SVarsha Kaverappa 	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
122390bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
1224cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
1225909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_copy(struct pldm_msgbuf * dst,struct pldm_msgbuf * src,size_t size,const char * description LIBPLDM_CC_UNUSED)122676712f69SAndrew Jeffery pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
122790bbe6c0SAndrew Jeffery 		  const char *description LIBPLDM_CC_UNUSED)
1228909bf7c2SVarsha Kaverappa {
122990bbe6c0SAndrew Jeffery 	if (!src->cursor || !dst->cursor) {
1230830c1eb4SAndrew Jeffery 		return -EINVAL;
1231909bf7c2SVarsha Kaverappa 	}
1232909bf7c2SVarsha Kaverappa 
1233909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX
1234909bf7c2SVarsha Kaverappa 	if (size > INTMAX_MAX) {
1235830c1eb4SAndrew Jeffery 		return -EOVERFLOW;
1236909bf7c2SVarsha Kaverappa 	}
1237909bf7c2SVarsha Kaverappa #endif
1238909bf7c2SVarsha Kaverappa 
12394f60fb77SAndrew Jeffery 	if (src->remaining >= (intmax_t)size &&
12404f60fb77SAndrew Jeffery 	    dst->remaining >= (intmax_t)size) {
1241909bf7c2SVarsha Kaverappa 		memcpy(dst->cursor, src->cursor, size);
1242909bf7c2SVarsha Kaverappa 		src->cursor += size;
12434f60fb77SAndrew Jeffery 		src->remaining -= (intmax_t)size;
1244909bf7c2SVarsha Kaverappa 		dst->cursor += size;
12454f60fb77SAndrew Jeffery 		dst->remaining -= (intmax_t)size;
1246c8df31c1SAndrew Jeffery 		return 0;
1247909bf7c2SVarsha Kaverappa 	}
1248c8df31c1SAndrew Jeffery 
12494f60fb77SAndrew Jeffery 	if (src->remaining >= INTMAX_MIN + (intmax_t)size) {
12504f60fb77SAndrew Jeffery 		src->remaining -= (intmax_t)size;
12514f60fb77SAndrew Jeffery 	}
12524f60fb77SAndrew Jeffery 
12534f60fb77SAndrew Jeffery 	if (dst->remaining >= INTMAX_MIN + (intmax_t)size) {
12544f60fb77SAndrew Jeffery 		dst->remaining -= (intmax_t)size;
12554f60fb77SAndrew Jeffery 	}
12564f60fb77SAndrew Jeffery 
12574f60fb77SAndrew Jeffery 	return -EOVERFLOW;
12584f60fb77SAndrew Jeffery }
12594f60fb77SAndrew Jeffery 
126090bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
12610a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
1262cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf * dst,struct pldm_msgbuf * src)12638b879600SAndrew Jeffery pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
12648b879600SAndrew Jeffery {
12658b879600SAndrew Jeffery 	void *ascii = NULL;
12668b879600SAndrew Jeffery 	size_t len = 0;
12678b879600SAndrew Jeffery 	int rc;
12688b879600SAndrew Jeffery 
12698b879600SAndrew Jeffery 	rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
12708b879600SAndrew Jeffery 	if (rc < 0) {
12718b879600SAndrew Jeffery 		return rc;
12728b879600SAndrew Jeffery 	}
12738b879600SAndrew Jeffery 
12740a1be3cbSAndrew Jeffery 	return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
12758b879600SAndrew Jeffery }
12768b879600SAndrew Jeffery 
127790bbe6c0SAndrew Jeffery LIBPLDM_CC_NONNULL
12780a1be3cbSAndrew Jeffery LIBPLDM_CC_WARN_UNUSED_RESULT
1279cb569bc5SAndrew Jeffery LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf * dst,struct pldm_msgbuf * src)128056f73f95SAndrew Jeffery pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
128156f73f95SAndrew Jeffery {
128256f73f95SAndrew Jeffery 	void *utf16 = NULL;
128356f73f95SAndrew Jeffery 	size_t len = 0;
128456f73f95SAndrew Jeffery 	int rc;
128556f73f95SAndrew Jeffery 
128656f73f95SAndrew Jeffery 	rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
128756f73f95SAndrew Jeffery 	if (rc < 0) {
128856f73f95SAndrew Jeffery 		return rc;
128956f73f95SAndrew Jeffery 	}
129056f73f95SAndrew Jeffery 
12910a1be3cbSAndrew Jeffery 	return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
129256f73f95SAndrew Jeffery }
129356f73f95SAndrew Jeffery 
1294c63f63a2SAndrew Jeffery #ifdef __cplusplus
1295c63f63a2SAndrew Jeffery }
1296c63f63a2SAndrew Jeffery #endif
1297c63f63a2SAndrew Jeffery 
129866c7723aSAndrew Jeffery #ifdef __cplusplus
129966c7723aSAndrew Jeffery #include <type_traits>
130066c7723aSAndrew Jeffery 
130166c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf * ctx,void * buf)130266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
130366c7723aSAndrew Jeffery 						void *buf)
130466c7723aSAndrew Jeffery {
1305e5f12538SAndrew Jeffery 	static_assert(std::is_same<uint8_t, T>::value);
130666c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint8(ctx, buf);
130766c7723aSAndrew Jeffery }
130866c7723aSAndrew Jeffery 
130966c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf * ctx,void * buf)131066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
131166c7723aSAndrew Jeffery 					       void *buf)
131266c7723aSAndrew Jeffery {
1313e5f12538SAndrew Jeffery 	static_assert(std::is_same<int8_t, T>::value);
131466c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int8(ctx, buf);
131566c7723aSAndrew Jeffery }
131666c7723aSAndrew Jeffery 
131766c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf * ctx,void * buf)131866c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
131966c7723aSAndrew Jeffery 						 void *buf)
132066c7723aSAndrew Jeffery {
1321e5f12538SAndrew Jeffery 	static_assert(std::is_same<uint16_t, T>::value);
132266c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint16(ctx, buf);
132366c7723aSAndrew Jeffery }
132466c7723aSAndrew Jeffery 
132566c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf * ctx,void * buf)132666c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
132766c7723aSAndrew Jeffery 						void *buf)
132866c7723aSAndrew Jeffery {
1329e5f12538SAndrew Jeffery 	static_assert(std::is_same<int16_t, T>::value);
133066c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int16(ctx, buf);
133166c7723aSAndrew Jeffery }
133266c7723aSAndrew Jeffery 
133366c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf * ctx,void * buf)133466c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
133566c7723aSAndrew Jeffery 						 void *buf)
133666c7723aSAndrew Jeffery {
1337e5f12538SAndrew Jeffery 	static_assert(std::is_same<uint32_t, T>::value);
133866c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint32(ctx, buf);
133966c7723aSAndrew Jeffery }
134066c7723aSAndrew Jeffery 
134166c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf * ctx,void * buf)134266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
134366c7723aSAndrew Jeffery 						void *buf)
134466c7723aSAndrew Jeffery {
1345e5f12538SAndrew Jeffery 	static_assert(std::is_same<int32_t, T>::value);
134666c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int32(ctx, buf);
134766c7723aSAndrew Jeffery }
134866c7723aSAndrew Jeffery 
134966c7723aSAndrew Jeffery template <typename T>
pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf * ctx,void * buf)135066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
135166c7723aSAndrew Jeffery 						 void *buf)
135266c7723aSAndrew Jeffery {
1353e5f12538SAndrew Jeffery 	static_assert(std::is_same<real32_t, T>::value);
135466c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_real32(ctx, buf);
135566c7723aSAndrew Jeffery }
135666c7723aSAndrew Jeffery #endif
135766c7723aSAndrew Jeffery 
1358c63f63a2SAndrew Jeffery #endif /* BUF_H */
1359