xref: /openbmc/libpldm/src/msgbuf.h (revision 76712f69)
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 
566c7723aSAndrew Jeffery /*
666c7723aSAndrew Jeffery  * Historically, many of the structs exposed in libpldm's public headers are
766c7723aSAndrew Jeffery  * defined with __attribute__((packed)). This is unfortunate: it gives the
866c7723aSAndrew Jeffery  * impression that a wire-format buffer can be cast to the message type to make
966c7723aSAndrew Jeffery  * the message's fields easily accessible. As it turns out, that's not
1066c7723aSAndrew Jeffery  * that's valid for several reasons:
1166c7723aSAndrew Jeffery  *
1266c7723aSAndrew Jeffery  * 1. Casting the wire-format buffer to a struct of the message type doesn't
1366c7723aSAndrew Jeffery  *    abstract the endianness of message field values
1466c7723aSAndrew Jeffery  *
1566c7723aSAndrew Jeffery  * 2. Some messages contain packed tagged union fields which cannot be properly
1666c7723aSAndrew Jeffery  *    described in a C struct.
1766c7723aSAndrew Jeffery  *
1866c7723aSAndrew Jeffery  * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
1966c7723aSAndrew Jeffery  * that is type-safe, spatially memory-safe, endian-safe, performant, and
2066c7723aSAndrew Jeffery  * free of undefined-behaviour. Message structs that are added to the public
2166c7723aSAndrew Jeffery  * library API should no-longer be marked __attribute__((packed)), and the
2266c7723aSAndrew Jeffery  * implementation of their encode and decode functions must exploit the msgbuf
2366c7723aSAndrew Jeffery  * API.
2466c7723aSAndrew Jeffery  *
2566c7723aSAndrew Jeffery  * However, we would like to allow implementation of codec functions in terms of
2666c7723aSAndrew Jeffery  * msgbuf APIs even if they're decoding a message into a (historically) packed
2766c7723aSAndrew Jeffery  * struct. Some of the complexity that follows is a consequence of the packed/
2866c7723aSAndrew Jeffery  * unpacked conflict.
2966c7723aSAndrew Jeffery  */
3066c7723aSAndrew Jeffery 
31c63f63a2SAndrew Jeffery #ifdef __cplusplus
3237dd6a3dSAndrew Jeffery /*
3337dd6a3dSAndrew Jeffery  * Fix up C11's _Static_assert() vs C++'s static_assert().
3437dd6a3dSAndrew Jeffery  *
3537dd6a3dSAndrew Jeffery  * Can we please have nice things for once.
3637dd6a3dSAndrew Jeffery  */
3737dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
3837dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__)
39c63f63a2SAndrew Jeffery extern "C" {
40c63f63a2SAndrew Jeffery #endif
41c63f63a2SAndrew Jeffery 
42b0c1d20aSAndrew Jeffery #include <libpldm/base.h>
43b0c1d20aSAndrew Jeffery #include <libpldm/pldm_types.h>
44c63f63a2SAndrew Jeffery 
4566c7723aSAndrew Jeffery #include "compiler.h"
4666c7723aSAndrew Jeffery 
47c63f63a2SAndrew Jeffery #include <assert.h>
48c63f63a2SAndrew Jeffery #include <endian.h>
49c63f63a2SAndrew Jeffery #include <limits.h>
50c63f63a2SAndrew Jeffery #include <stdbool.h>
5166c7723aSAndrew Jeffery #include <stdint.h>
52c63f63a2SAndrew Jeffery #include <string.h>
53c63f63a2SAndrew Jeffery #include <sys/types.h>
54c63f63a2SAndrew Jeffery 
552ff8cf89SAndrew Jeffery /*
562ff8cf89SAndrew Jeffery  * We can't use static_assert() outside of some other C construct. Deal
572ff8cf89SAndrew Jeffery  * with high-level global assertions by burying them in an unused struct
582ff8cf89SAndrew Jeffery  * declaration, that has a sole member for compliance with the requirement that
592ff8cf89SAndrew Jeffery  * types must have a size.
602ff8cf89SAndrew Jeffery */
612ff8cf89SAndrew Jeffery static struct {
622ff8cf89SAndrew Jeffery 	static_assert(
632ff8cf89SAndrew Jeffery 		INTMAX_MAX != SIZE_MAX,
642ff8cf89SAndrew Jeffery 		"Extraction and insertion value comparisons may be broken");
652ff8cf89SAndrew Jeffery 	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
662ff8cf89SAndrew Jeffery 		      "Extraction and insertion arithmetic may be broken");
672ff8cf89SAndrew Jeffery 	int compliance;
682ff8cf89SAndrew Jeffery } build_assertions __attribute__((unused));
692ff8cf89SAndrew Jeffery 
70c63f63a2SAndrew Jeffery struct pldm_msgbuf {
71062c8762SThu Nguyen 	uint8_t *cursor;
722ff8cf89SAndrew Jeffery 	intmax_t remaining;
73c63f63a2SAndrew Jeffery };
74c63f63a2SAndrew Jeffery 
75c63f63a2SAndrew Jeffery /**
76c63f63a2SAndrew Jeffery  * @brief Initialize pldm buf struct for buf extractor
77c63f63a2SAndrew Jeffery  *
78c63f63a2SAndrew Jeffery  * @param[out] ctx - pldm_msgbuf context for extractor
79c63f63a2SAndrew Jeffery  * @param[in] minsize - The minimum required length of buffer `buf`
80c63f63a2SAndrew Jeffery  * @param[in] buf - buffer to be extracted
81c63f63a2SAndrew Jeffery  * @param[in] len - size of buffer
82c63f63a2SAndrew Jeffery  *
83c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
84c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or
85c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
86c63f63a2SAndrew Jeffery  */
87*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
88*76712f69SAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
89*76712f69SAndrew Jeffery 		 size_t len)
90c63f63a2SAndrew Jeffery {
91c63f63a2SAndrew Jeffery 	if (!ctx || !buf) {
92c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
93c63f63a2SAndrew Jeffery 	}
94c63f63a2SAndrew Jeffery 
952ff8cf89SAndrew Jeffery 	if ((minsize > len)) {
96c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
97c63f63a2SAndrew Jeffery 	}
98c63f63a2SAndrew Jeffery 
992ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
1002ff8cf89SAndrew Jeffery 	if (len > INTMAX_MAX) {
1012ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
1022ff8cf89SAndrew Jeffery 	}
1032ff8cf89SAndrew Jeffery #endif
1042ff8cf89SAndrew Jeffery 
10507febdbbSAndrew Jeffery 	if ((uintptr_t)buf + len < len) {
106c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
107c63f63a2SAndrew Jeffery 	}
108c63f63a2SAndrew Jeffery 
109c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
1102ff8cf89SAndrew Jeffery 	ctx->remaining = (intmax_t)len;
111c63f63a2SAndrew Jeffery 
112c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
113c63f63a2SAndrew Jeffery }
114c63f63a2SAndrew Jeffery 
115c63f63a2SAndrew Jeffery /**
116c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
117c63f63a2SAndrew Jeffery  *
118c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
119c63f63a2SAndrew Jeffery  *
120c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
121c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
122c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
123c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
124c63f63a2SAndrew Jeffery  * pointer.
125c63f63a2SAndrew Jeffery  */
126*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
127*76712f69SAndrew Jeffery pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
128c63f63a2SAndrew Jeffery {
129c63f63a2SAndrew Jeffery 	if (!ctx) {
130c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
131c63f63a2SAndrew Jeffery 	}
132c63f63a2SAndrew Jeffery 
133c63f63a2SAndrew Jeffery 	return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
134c63f63a2SAndrew Jeffery }
135c63f63a2SAndrew Jeffery 
136c63f63a2SAndrew Jeffery /**
137db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
138db7b8324SAndrew Jeffery  *
139db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
140db7b8324SAndrew Jeffery  *
141db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
142db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
143db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
144db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
145db7b8324SAndrew Jeffery  * pointer.
146db7b8324SAndrew Jeffery  */
147*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
148*76712f69SAndrew Jeffery pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
149db7b8324SAndrew Jeffery {
150db7b8324SAndrew Jeffery 	if (!ctx) {
151db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
152db7b8324SAndrew Jeffery 	}
153db7b8324SAndrew Jeffery 
154db7b8324SAndrew Jeffery 	return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
155db7b8324SAndrew Jeffery }
156db7b8324SAndrew Jeffery 
157db7b8324SAndrew Jeffery /**
158c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
159c63f63a2SAndrew Jeffery  *
160c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
161c63f63a2SAndrew Jeffery  *
162c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
163c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
164c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
165c63f63a2SAndrew Jeffery  * bounds of the buffer.
166c63f63a2SAndrew Jeffery  */
167*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
168*76712f69SAndrew Jeffery pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
169c63f63a2SAndrew Jeffery {
170c63f63a2SAndrew Jeffery 	int valid;
171c63f63a2SAndrew Jeffery 
172c63f63a2SAndrew Jeffery 	if (!ctx) {
173c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
174c63f63a2SAndrew Jeffery 	}
175c63f63a2SAndrew Jeffery 
176c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
177c63f63a2SAndrew Jeffery 
178c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
179c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
180c63f63a2SAndrew Jeffery 
181c63f63a2SAndrew Jeffery 	return valid;
182c63f63a2SAndrew Jeffery }
183c63f63a2SAndrew Jeffery 
184c63f63a2SAndrew Jeffery /**
185db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
186db7b8324SAndrew Jeffery  * has been completely consumed without overflow
187db7b8324SAndrew Jeffery  *
188db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
189db7b8324SAndrew Jeffery  *
190db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
191db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
192db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
193db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
194db7b8324SAndrew Jeffery  */
195*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
196*76712f69SAndrew Jeffery pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
197db7b8324SAndrew Jeffery {
198db7b8324SAndrew Jeffery 	int consumed;
199db7b8324SAndrew Jeffery 
200db7b8324SAndrew Jeffery 	if (!ctx) {
201db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
202db7b8324SAndrew Jeffery 	}
203db7b8324SAndrew Jeffery 
204db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
205db7b8324SAndrew Jeffery 
206db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
207db7b8324SAndrew Jeffery 	ctx->remaining = 0;
208db7b8324SAndrew Jeffery 
209db7b8324SAndrew Jeffery 	return consumed;
210db7b8324SAndrew Jeffery }
211db7b8324SAndrew Jeffery 
21266c7723aSAndrew Jeffery /*
21366c7723aSAndrew Jeffery  * Exploit the pre-processor to perform type checking by macro substitution.
21466c7723aSAndrew Jeffery  *
21566c7723aSAndrew Jeffery  * A C type is defined by its alignment as well as its object
21666c7723aSAndrew Jeffery  * size, and compilers have a hammer to enforce it in the form of
21766c7723aSAndrew Jeffery  * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
21866c7723aSAndrew Jeffery  * the libpldm public API this presents a problem: Naively attempting to use the
21966c7723aSAndrew Jeffery  * msgbuf APIs on a member of a packed struct would yield an error.
22066c7723aSAndrew Jeffery  *
22166c7723aSAndrew Jeffery  * The msgbuf APIs are implemented such that data is moved through unaligned
22266c7723aSAndrew Jeffery  * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
22366c7723aSAndrew Jeffery  * make the object pointers take a trip through `void *` at its API boundary.
22466c7723aSAndrew Jeffery  * That presents a bit too much of an opportunity to non-surgically remove your
22566c7723aSAndrew Jeffery  * own foot, so here we set about doing something to mitigate that as well.
22666c7723aSAndrew Jeffery  *
22766c7723aSAndrew Jeffery  * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
22866c7723aSAndrew Jeffery  * only for the purpose of object sizes, disregarding alignment. We have a few
22966c7723aSAndrew Jeffery  * constraints that cause some headaches:
23066c7723aSAndrew Jeffery  *
23166c7723aSAndrew Jeffery  * 1. We have to perform the type-check before a call through a C function,
23266c7723aSAndrew Jeffery  *    as the function must take the object pointer argument as `void *`.
23366c7723aSAndrew Jeffery  *    Essentially, this constrains us to doing something with macros.
23466c7723aSAndrew Jeffery  *
23566c7723aSAndrew Jeffery  * 2. While libpldm is a C library, its test suite is written in C++ to take
23666c7723aSAndrew Jeffery  *    advantage of gtest.
23766c7723aSAndrew Jeffery  *
23866c7723aSAndrew Jeffery  * 3. Ideally we'd do something with C's `static_assert()`, however
23966c7723aSAndrew Jeffery  *    `static_assert()` is defined as void, and as we're constrained to macros,
24066c7723aSAndrew Jeffery  *    using `static_assert()` would require a statement-expression
24166c7723aSAndrew Jeffery  *
24266c7723aSAndrew Jeffery  * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
24366c7723aSAndrew Jeffery  *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
24466c7723aSAndrew Jeffery  *    the purpose of enabling statement-expressions in this one instance.
24566c7723aSAndrew Jeffery  *
24666c7723aSAndrew Jeffery  * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
24766c7723aSAndrew Jeffery  *    however it's implemented in terms of `_Generic()`, which is not available
24866c7723aSAndrew Jeffery  *    in C++.
24966c7723aSAndrew Jeffery  *
25066c7723aSAndrew Jeffery  * Combined this means we need separate solutions for C and C++.
25166c7723aSAndrew Jeffery  *
25266c7723aSAndrew Jeffery  * For C, as we don't have statement-expressions, we need to exploit some other
25366c7723aSAndrew Jeffery  * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
25466c7723aSAndrew Jeffery  * API function call. We also have to take care of the fact that the call-sites
25566c7723aSAndrew Jeffery  * may be in the context of a variable assignment for error-handling purposes.
25666c7723aSAndrew Jeffery  * The key observation is that we can use the comma operator as a sequence point
25766c7723aSAndrew Jeffery  * to order the type check before the API call, discarding the "result" value of
25866c7723aSAndrew Jeffery  * the type check and yielding the return value of the API call.
25966c7723aSAndrew Jeffery  *
26066c7723aSAndrew Jeffery  * C++ could be less of a headache than the C as we can leverage template
26166c7723aSAndrew Jeffery  * functions. An advantage of template functions is that while their definition
26266c7723aSAndrew Jeffery  * is driven by instantion, the definition does not appear at the source
26366c7723aSAndrew Jeffery  * location of the instantation, which gives it a great leg-up over the problems
26466c7723aSAndrew Jeffery  * we have in the C path. However, the use of the msgbuf APIs in the test suite
26566c7723aSAndrew Jeffery  * still makes things somewhat tricky, as the call-sites in the test suite are
26666c7723aSAndrew Jeffery  * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
26766c7723aSAndrew Jeffery  * takes both the object type and the required type as template arguments, and
26866c7723aSAndrew Jeffery  * then define the object pointer parameter as `void *` for a call through to
26966c7723aSAndrew Jeffery  * the appropriate msgbuf API. However, because the msgbuf API call-sites are
27066c7723aSAndrew Jeffery  * encapsulated in gtest macros, use of commas in the template specification
27166c7723aSAndrew Jeffery  * causes pre-processor confusion. In this way we're constrained to only one
27266c7723aSAndrew Jeffery  * template argument per function.
27366c7723aSAndrew Jeffery  *
27466c7723aSAndrew Jeffery  * Implement the C++ path using template functions that take the destination
27566c7723aSAndrew Jeffery  * object type as a template argument, while the name of the function symbols
27666c7723aSAndrew Jeffery  * are derived from the required type. The manual implementations of these
27766c7723aSAndrew Jeffery  * appear at the end of the header. The type safety is actually enforced
27866c7723aSAndrew Jeffery  * by `static_assert()` this time, as we can use statements as we're not
27966c7723aSAndrew Jeffery  * constrained to an expression in the templated function body.
28066c7723aSAndrew Jeffery  *
28166c7723aSAndrew Jeffery  * The invocations of pldm_msgbuf_extract_typecheck() typically result in
28266c7723aSAndrew Jeffery  * double-evaluation of some arguments. We're not yet bothered by this for two
28366c7723aSAndrew Jeffery  * reasons:
28466c7723aSAndrew Jeffery  *
28566c7723aSAndrew Jeffery  * 1. The nature of the current call-sites are such that there are no
28666c7723aSAndrew Jeffery  *    argument expressions that result in undesirable side-effects
28766c7723aSAndrew Jeffery  *
28866c7723aSAndrew Jeffery  * 2. It's an API internal to the libpldm implementation, and we can fix things
28966c7723aSAndrew Jeffery  *    whenever something crops up the violates the observation in 1.
29066c7723aSAndrew Jeffery  */
29166c7723aSAndrew Jeffery #ifdef __cplusplus
29266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
29366c7723aSAndrew Jeffery 	pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
29466c7723aSAndrew Jeffery #else
29566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
29666c7723aSAndrew Jeffery 	(pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
29766c7723aSAndrew Jeffery #endif
29866c7723aSAndrew Jeffery 
299db7b8324SAndrew Jeffery /**
300c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
301c63f63a2SAndrew Jeffery  *
302c63f63a2SAndrew Jeffery  * @param[inout] ctx - pldm_msgbuf context for extractor
303c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
304c63f63a2SAndrew Jeffery  *
305c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
306c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
307c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
308c63f63a2SAndrew Jeffery  */
30966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst)                                    \
31066c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8,     \
31166c7723aSAndrew Jeffery 				      dst, ctx, dst)
312*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
31366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
314*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
315c63f63a2SAndrew Jeffery {
316c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
317c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
318c63f63a2SAndrew Jeffery 	}
319c63f63a2SAndrew Jeffery 
3202ff8cf89SAndrew Jeffery 	if (ctx->remaining == INTMAX_MIN) {
3212ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3222ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3232ff8cf89SAndrew Jeffery 	}
32466c7723aSAndrew Jeffery 	ctx->remaining -= sizeof(uint8_t);
325c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
326c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
327c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
328c63f63a2SAndrew Jeffery 	}
329c63f63a2SAndrew Jeffery 
33066c7723aSAndrew Jeffery 	memcpy(dst, ctx->cursor, sizeof(uint8_t));
33166c7723aSAndrew Jeffery 
332c63f63a2SAndrew Jeffery 	ctx->cursor++;
333c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
334c63f63a2SAndrew Jeffery }
335c63f63a2SAndrew Jeffery 
33666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst)                                     \
33766c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst,  \
33866c7723aSAndrew Jeffery 				      ctx, dst)
339*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
34066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
341*76712f69SAndrew Jeffery pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
342c63f63a2SAndrew Jeffery {
343c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
344c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
345c63f63a2SAndrew Jeffery 	}
346c63f63a2SAndrew Jeffery 
3472ff8cf89SAndrew Jeffery 	if (ctx->remaining == INTMAX_MIN) {
3482ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3492ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3502ff8cf89SAndrew Jeffery 	}
35166c7723aSAndrew Jeffery 	ctx->remaining -= sizeof(int8_t);
352c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
353c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
354c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
355c63f63a2SAndrew Jeffery 	}
356c63f63a2SAndrew Jeffery 
35766c7723aSAndrew Jeffery 	memcpy(dst, ctx->cursor, sizeof(int8_t));
358c63f63a2SAndrew Jeffery 	ctx->cursor++;
359c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
360c63f63a2SAndrew Jeffery }
361c63f63a2SAndrew Jeffery 
36266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst)                                   \
36366c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16,   \
36466c7723aSAndrew Jeffery 				      dst, ctx, dst)
365*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
36666c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
367*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
368c63f63a2SAndrew Jeffery {
369c63f63a2SAndrew Jeffery 	uint16_t ldst;
370c63f63a2SAndrew Jeffery 
371c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
372c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
373c63f63a2SAndrew Jeffery 	}
374c63f63a2SAndrew Jeffery 
3752ff8cf89SAndrew Jeffery 	// Check for underflow while tracking the magnitude of the buffer overflow
3762ff8cf89SAndrew Jeffery 	static_assert(
3772ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
3782ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
3792ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
3802ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
3812ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3822ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3832ff8cf89SAndrew Jeffery 	}
3842ff8cf89SAndrew Jeffery 
385c63f63a2SAndrew Jeffery 	// Check for buffer overflow. If we overflow, account for the request as
386c63f63a2SAndrew Jeffery 	// negative values in ctx->remaining. This way we can debug how far
387c63f63a2SAndrew Jeffery 	// we've overflowed.
388c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
389c63f63a2SAndrew Jeffery 
390c63f63a2SAndrew Jeffery 	// Prevent the access if it would overflow. First, assert so we blow up
391c63f63a2SAndrew Jeffery 	// the test suite right at the point of failure. However, cater to
392c63f63a2SAndrew Jeffery 	// -DNDEBUG by explicitly testing that the access is valid.
393c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
394c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
395c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
396c63f63a2SAndrew Jeffery 	}
397c63f63a2SAndrew Jeffery 
398c63f63a2SAndrew Jeffery 	// Use memcpy() to have the compiler deal with any alignment
399c63f63a2SAndrew Jeffery 	// issues on the target architecture
400c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
401c63f63a2SAndrew Jeffery 
402c63f63a2SAndrew Jeffery 	// Only assign the target value once it's correctly decoded
40366c7723aSAndrew Jeffery 	ldst = le16toh(ldst);
40466c7723aSAndrew Jeffery 
40566c7723aSAndrew Jeffery 	// Allow storing to unaligned
40666c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
40766c7723aSAndrew Jeffery 
408c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
409c63f63a2SAndrew Jeffery 
410c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
411c63f63a2SAndrew Jeffery }
412c63f63a2SAndrew Jeffery 
41366c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst)                                    \
41466c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16,     \
41566c7723aSAndrew Jeffery 				      dst, ctx, dst)
416*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
41766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
418*76712f69SAndrew Jeffery pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
419c63f63a2SAndrew Jeffery {
420c63f63a2SAndrew Jeffery 	int16_t ldst;
421c63f63a2SAndrew Jeffery 
422c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
423c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
424c63f63a2SAndrew Jeffery 	}
425c63f63a2SAndrew Jeffery 
4262ff8cf89SAndrew Jeffery 	static_assert(
4272ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4282ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4292ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
4302ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4312ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
4322ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
4332ff8cf89SAndrew Jeffery 	}
434c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
435c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
436c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
437c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
438c63f63a2SAndrew Jeffery 	}
439c63f63a2SAndrew Jeffery 
440c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
441c63f63a2SAndrew Jeffery 
44266c7723aSAndrew Jeffery 	ldst = le16toh(ldst);
44366c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
444c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
445c63f63a2SAndrew Jeffery 
446c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
447c63f63a2SAndrew Jeffery }
448c63f63a2SAndrew Jeffery 
44966c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst)                                   \
45066c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32,   \
45166c7723aSAndrew Jeffery 				      dst, ctx, dst)
452*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
45366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
454*76712f69SAndrew Jeffery pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
455c63f63a2SAndrew Jeffery {
456c63f63a2SAndrew Jeffery 	uint32_t ldst;
457c63f63a2SAndrew Jeffery 
458c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
459c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
460c63f63a2SAndrew Jeffery 	}
461c63f63a2SAndrew Jeffery 
4622ff8cf89SAndrew Jeffery 	static_assert(
4632ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4642ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4652ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
4662ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4672ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
4682ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
4692ff8cf89SAndrew Jeffery 	}
470c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
471c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
472c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
473c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
474c63f63a2SAndrew Jeffery 	}
475c63f63a2SAndrew Jeffery 
476c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
477c63f63a2SAndrew Jeffery 
47866c7723aSAndrew Jeffery 	ldst = le32toh(ldst);
47966c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
480c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
481c63f63a2SAndrew Jeffery 
482c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
483c63f63a2SAndrew Jeffery }
484c63f63a2SAndrew Jeffery 
48566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst)                                    \
48666c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32,     \
48766c7723aSAndrew Jeffery 				      dst, ctx, dst)
488*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
48966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
490*76712f69SAndrew Jeffery pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
491c63f63a2SAndrew Jeffery {
492c63f63a2SAndrew Jeffery 	int32_t ldst;
493c63f63a2SAndrew Jeffery 
494c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
495c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
496c63f63a2SAndrew Jeffery 	}
497c63f63a2SAndrew Jeffery 
4982ff8cf89SAndrew Jeffery 	static_assert(
4992ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
5002ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
5012ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
5022ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
5032ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
5042ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
5052ff8cf89SAndrew Jeffery 	}
506c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
507c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
508c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
509c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
510c63f63a2SAndrew Jeffery 	}
511c63f63a2SAndrew Jeffery 
512c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
513c63f63a2SAndrew Jeffery 
51466c7723aSAndrew Jeffery 	ldst = le32toh(ldst);
51566c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
516c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
517c63f63a2SAndrew Jeffery 
518c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
519c63f63a2SAndrew Jeffery }
520c63f63a2SAndrew Jeffery 
52166c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst)                                   \
52266c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32,   \
52366c7723aSAndrew Jeffery 				      dst, ctx, dst)
524*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
52566c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
526*76712f69SAndrew Jeffery pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
527c63f63a2SAndrew Jeffery {
528c63f63a2SAndrew Jeffery 	uint32_t ldst;
529c63f63a2SAndrew Jeffery 
53066c7723aSAndrew Jeffery 	_Static_assert(sizeof(real32_t) == sizeof(ldst),
53166c7723aSAndrew Jeffery 		       "Mismatched type sizes for dst and ldst");
53266c7723aSAndrew Jeffery 
533c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
534c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
535c63f63a2SAndrew Jeffery 	}
536c63f63a2SAndrew Jeffery 
5372ff8cf89SAndrew Jeffery 	static_assert(
5382ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
5392ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
5402ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
5412ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
5422ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
5432ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
5442ff8cf89SAndrew Jeffery 	}
545c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
546c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
547c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
548c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
549c63f63a2SAndrew Jeffery 	}
550c63f63a2SAndrew Jeffery 
551c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
552c63f63a2SAndrew Jeffery 	ldst = le32toh(ldst);
55366c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
55466c7723aSAndrew Jeffery 	ctx->cursor += sizeof(ldst);
555c63f63a2SAndrew Jeffery 
556c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
557c63f63a2SAndrew Jeffery }
558c63f63a2SAndrew Jeffery 
55966c7723aSAndrew Jeffery /**
56066c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the lvalue named by dst.
56166c7723aSAndrew Jeffery  *
56266c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
56366c7723aSAndrew Jeffery  * @param dst The lvalue into which the field at the msgbuf cursor should be
56466c7723aSAndrew Jeffery  *            extracted
56566c7723aSAndrew Jeffery  *
56666c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
56766c7723aSAndrew Jeffery  */
568c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
56966c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
57066c7723aSAndrew Jeffery 		uint8_t: pldm__msgbuf_extract_uint8,                           \
57166c7723aSAndrew Jeffery 		int8_t: pldm__msgbuf_extract_int8,                             \
57266c7723aSAndrew Jeffery 		uint16_t: pldm__msgbuf_extract_uint16,                         \
57366c7723aSAndrew Jeffery 		int16_t: pldm__msgbuf_extract_int16,                           \
57466c7723aSAndrew Jeffery 		uint32_t: pldm__msgbuf_extract_uint32,                         \
57566c7723aSAndrew Jeffery 		int32_t: pldm__msgbuf_extract_int32,                           \
57666c7723aSAndrew Jeffery 		real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
57766c7723aSAndrew Jeffery 
57866c7723aSAndrew Jeffery /**
57966c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the object pointed-to by dst.
58066c7723aSAndrew Jeffery  *
58166c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
58266c7723aSAndrew Jeffery  * @param dst The pointer to the object into which the field at the msgbuf
58366c7723aSAndrew Jeffery  *            cursor should be extracted
58466c7723aSAndrew Jeffery  *
58566c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
58666c7723aSAndrew Jeffery  */
58766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst)                                        \
58866c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
58966c7723aSAndrew Jeffery 		uint8_t *: pldm__msgbuf_extract_uint8,                         \
59066c7723aSAndrew Jeffery 		int8_t *: pldm__msgbuf_extract_int8,                           \
59166c7723aSAndrew Jeffery 		uint16_t *: pldm__msgbuf_extract_uint16,                       \
59266c7723aSAndrew Jeffery 		int16_t *: pldm__msgbuf_extract_int16,                         \
59366c7723aSAndrew Jeffery 		uint32_t *: pldm__msgbuf_extract_uint32,                       \
59466c7723aSAndrew Jeffery 		int32_t *: pldm__msgbuf_extract_int32,                         \
59566c7723aSAndrew Jeffery 		real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
596c63f63a2SAndrew Jeffery 
597*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
598*76712f69SAndrew Jeffery pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
599*76712f69SAndrew Jeffery 				size_t count)
600369b121aSAndrew Jeffery {
601369b121aSAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
602369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
603369b121aSAndrew Jeffery 	}
604369b121aSAndrew Jeffery 
605369b121aSAndrew Jeffery 	if (!count) {
606369b121aSAndrew Jeffery 		return PLDM_SUCCESS;
607369b121aSAndrew Jeffery 	}
608369b121aSAndrew Jeffery 
6092ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
6102ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
611369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
612369b121aSAndrew Jeffery 	}
6132ff8cf89SAndrew Jeffery #endif
614369b121aSAndrew Jeffery 
6152ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
6162ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6172ff8cf89SAndrew Jeffery 	}
6182ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)count;
619369b121aSAndrew Jeffery 	assert(ctx->remaining >= 0);
620369b121aSAndrew Jeffery 	if (ctx->remaining < 0) {
621369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
622369b121aSAndrew Jeffery 	}
623369b121aSAndrew Jeffery 
624a065eccbSAndrew Jeffery 	memcpy(dst, ctx->cursor, count);
625a065eccbSAndrew Jeffery 	ctx->cursor += count;
626369b121aSAndrew Jeffery 
627369b121aSAndrew Jeffery 	return PLDM_SUCCESS;
628369b121aSAndrew Jeffery }
629369b121aSAndrew Jeffery 
630369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
63137dd6a3dSAndrew Jeffery 	_Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
63237dd6a3dSAndrew Jeffery 								     count)
633369b121aSAndrew Jeffery 
634*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
635*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
636062c8762SThu Nguyen {
637062c8762SThu Nguyen 	uint32_t val = htole32(src);
638062c8762SThu Nguyen 
639062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
640062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
641062c8762SThu Nguyen 	}
642062c8762SThu Nguyen 
6432ff8cf89SAndrew Jeffery 	static_assert(
6442ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
6452ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
6462ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
6472ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
6482ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
6492ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6502ff8cf89SAndrew Jeffery 	}
651062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
652062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
653062c8762SThu Nguyen 	if (ctx->remaining < 0) {
654062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
655062c8762SThu Nguyen 	}
656062c8762SThu Nguyen 
657062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
658062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
659062c8762SThu Nguyen 
660062c8762SThu Nguyen 	return PLDM_SUCCESS;
661062c8762SThu Nguyen }
662062c8762SThu Nguyen 
663*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
664*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
665062c8762SThu Nguyen {
666062c8762SThu Nguyen 	uint16_t val = htole16(src);
667062c8762SThu Nguyen 
668062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
669062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
670062c8762SThu Nguyen 	}
671062c8762SThu Nguyen 
6722ff8cf89SAndrew Jeffery 	static_assert(
6732ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
6742ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
6752ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
6762ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
6772ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
6782ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6792ff8cf89SAndrew Jeffery 	}
680062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
681062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
682062c8762SThu Nguyen 	if (ctx->remaining < 0) {
683062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
684062c8762SThu Nguyen 	}
685062c8762SThu Nguyen 
686062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
687062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
688062c8762SThu Nguyen 
689062c8762SThu Nguyen 	return PLDM_SUCCESS;
690062c8762SThu Nguyen }
691062c8762SThu Nguyen 
692*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
693*76712f69SAndrew Jeffery pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
694062c8762SThu Nguyen {
695062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
696062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
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");
7032ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7042ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7052ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7062ff8cf89SAndrew Jeffery 	}
707062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
708062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
709062c8762SThu Nguyen 	if (ctx->remaining < 0) {
710062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
711062c8762SThu Nguyen 	}
712062c8762SThu Nguyen 
713062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
714062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
715062c8762SThu Nguyen 
716062c8762SThu Nguyen 	return PLDM_SUCCESS;
717062c8762SThu Nguyen }
718062c8762SThu Nguyen 
719*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
720*76712f69SAndrew Jeffery pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
721062c8762SThu Nguyen {
722062c8762SThu Nguyen 	int32_t val = htole32(src);
723062c8762SThu Nguyen 
724062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
725062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
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");
7322ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7332ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7342ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7352ff8cf89SAndrew Jeffery 	}
736062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
737062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
738062c8762SThu Nguyen 	if (ctx->remaining < 0) {
739062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
740062c8762SThu Nguyen 	}
741062c8762SThu Nguyen 
742062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
743062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
744062c8762SThu Nguyen 
745062c8762SThu Nguyen 	return PLDM_SUCCESS;
746062c8762SThu Nguyen }
747062c8762SThu Nguyen 
748*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
749*76712f69SAndrew Jeffery pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
750062c8762SThu Nguyen {
751062c8762SThu Nguyen 	int16_t val = htole16(src);
752062c8762SThu Nguyen 
753062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
754062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
755062c8762SThu Nguyen 	}
756062c8762SThu Nguyen 
7572ff8cf89SAndrew Jeffery 	static_assert(
7582ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7592ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7602ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
7612ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7622ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7632ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7642ff8cf89SAndrew Jeffery 	}
765062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
766062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
767062c8762SThu Nguyen 	if (ctx->remaining < 0) {
768062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
769062c8762SThu Nguyen 	}
770062c8762SThu Nguyen 
771062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
772062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
773062c8762SThu Nguyen 
774062c8762SThu Nguyen 	return PLDM_SUCCESS;
775062c8762SThu Nguyen }
776062c8762SThu Nguyen 
777*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
778*76712f69SAndrew Jeffery pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
779062c8762SThu Nguyen {
780062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
781062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
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");
7882ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7892ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7902ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7912ff8cf89SAndrew Jeffery 	}
792062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
793062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
794062c8762SThu Nguyen 	if (ctx->remaining < 0) {
795062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
796062c8762SThu Nguyen 	}
797062c8762SThu Nguyen 
798062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
799062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
800062c8762SThu Nguyen 
801062c8762SThu Nguyen 	return PLDM_SUCCESS;
802062c8762SThu Nguyen }
803062c8762SThu Nguyen 
804062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
80537dd6a3dSAndrew Jeffery 	_Generic((src),                                                        \
80637dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_uint8,                             \
80737dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_insert_int8,                               \
80837dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_insert_uint16,                           \
80937dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_insert_int16,                             \
81037dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_insert_uint32,                           \
81137dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_insert_int32)(dst, src)
812062c8762SThu Nguyen 
813*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
814*76712f69SAndrew Jeffery pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
815062c8762SThu Nguyen 			       size_t count)
816062c8762SThu Nguyen {
817062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !src) {
818062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
819062c8762SThu Nguyen 	}
820062c8762SThu Nguyen 
821062c8762SThu Nguyen 	if (!count) {
822062c8762SThu Nguyen 		return PLDM_SUCCESS;
823062c8762SThu Nguyen 	}
824062c8762SThu Nguyen 
8252ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
8262ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
827062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
828062c8762SThu Nguyen 	}
8292ff8cf89SAndrew Jeffery #endif
830062c8762SThu Nguyen 
8312ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
8322ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
8332ff8cf89SAndrew Jeffery 	}
8342ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)count;
835062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
836062c8762SThu Nguyen 	if (ctx->remaining < 0) {
837062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
838062c8762SThu Nguyen 	}
839062c8762SThu Nguyen 
840a065eccbSAndrew Jeffery 	memcpy(ctx->cursor, src, count);
841a065eccbSAndrew Jeffery 	ctx->cursor += count;
842062c8762SThu Nguyen 
843062c8762SThu Nguyen 	return PLDM_SUCCESS;
844062c8762SThu Nguyen }
845062c8762SThu Nguyen 
846062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count)                              \
84737dd6a3dSAndrew Jeffery 	_Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src,  \
84837dd6a3dSAndrew Jeffery 								    count)
849062c8762SThu Nguyen 
850*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
851*76712f69SAndrew Jeffery pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
852*76712f69SAndrew Jeffery 			  void **cursor)
853062c8762SThu Nguyen {
854062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor) {
855062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
856062c8762SThu Nguyen 	}
857062c8762SThu Nguyen 
8582ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
8592ff8cf89SAndrew Jeffery 	if (required > INTMAX_MAX) {
860062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
861062c8762SThu Nguyen 	}
8622ff8cf89SAndrew Jeffery #endif
863062c8762SThu Nguyen 
8642ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
8652ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
8662ff8cf89SAndrew Jeffery 	}
8672ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)required;
868062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
869062c8762SThu Nguyen 	if (ctx->remaining < 0) {
870062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
871062c8762SThu Nguyen 	}
872062c8762SThu Nguyen 
873062c8762SThu Nguyen 	*cursor = ctx->cursor;
874062c8762SThu Nguyen 	ctx->cursor += required;
875062c8762SThu Nguyen 
876062c8762SThu Nguyen 	return PLDM_SUCCESS;
877062c8762SThu Nguyen }
878062c8762SThu Nguyen 
879*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
880*76712f69SAndrew Jeffery pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
881062c8762SThu Nguyen {
882062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
883062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
884062c8762SThu Nguyen 	}
885062c8762SThu Nguyen 
886062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
887062c8762SThu Nguyen 	if (ctx->remaining < 0) {
888062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
889062c8762SThu Nguyen 	}
890062c8762SThu Nguyen 
891062c8762SThu Nguyen 	*cursor = ctx->cursor;
892062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
893062c8762SThu Nguyen 	*len = ctx->remaining;
894062c8762SThu Nguyen 	ctx->remaining = 0;
895062c8762SThu Nguyen 
896062c8762SThu Nguyen 	return PLDM_SUCCESS;
897062c8762SThu Nguyen }
898909bf7c2SVarsha Kaverappa 
899909bf7c2SVarsha Kaverappa /**
900909bf7c2SVarsha Kaverappa  * @brief pldm_msgbuf copy data between two msg buffers
901909bf7c2SVarsha Kaverappa  *
902909bf7c2SVarsha Kaverappa  * @param[inout] src - pldm_msgbuf for source from where value should be copied
903909bf7c2SVarsha Kaverappa  * @param[inout] dst - destination of copy from source
904909bf7c2SVarsha Kaverappa  * @param[in] size - size of data to be copied
905909bf7c2SVarsha Kaverappa  * @param[in] description - description of data copied
906909bf7c2SVarsha Kaverappa  *
907909bf7c2SVarsha Kaverappa  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
908909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_LENGTH otherwise.
909909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_DATA if input is invalid
910909bf7c2SVarsha Kaverappa  */
911909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name)                                 \
912909bf7c2SVarsha Kaverappa 	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
913*76712f69SAndrew Jeffery __attribute__((always_inline)) static inline int
914909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
915*76712f69SAndrew Jeffery pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
916909bf7c2SVarsha Kaverappa 		  const char *description)
917909bf7c2SVarsha Kaverappa {
918909bf7c2SVarsha Kaverappa 	if (!src || !src->cursor || !dst || !dst->cursor || !description) {
919909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_DATA;
920909bf7c2SVarsha Kaverappa 	}
921909bf7c2SVarsha Kaverappa 
922909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX
923909bf7c2SVarsha Kaverappa 	if (size > INTMAX_MAX) {
924909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
925909bf7c2SVarsha Kaverappa 	}
926909bf7c2SVarsha Kaverappa #endif
927909bf7c2SVarsha Kaverappa 
928909bf7c2SVarsha Kaverappa 	if (src->remaining < INTMAX_MIN + (intmax_t)size) {
929909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
930909bf7c2SVarsha Kaverappa 	}
931909bf7c2SVarsha Kaverappa 
932909bf7c2SVarsha Kaverappa 	if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
933909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
934909bf7c2SVarsha Kaverappa 	}
935909bf7c2SVarsha Kaverappa 
936909bf7c2SVarsha Kaverappa 	src->remaining -= (intmax_t)size;
937909bf7c2SVarsha Kaverappa 	assert(src->remaining >= 0);
938909bf7c2SVarsha Kaverappa 	if (src->remaining < 0) {
939909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
940909bf7c2SVarsha Kaverappa 	}
941909bf7c2SVarsha Kaverappa 
942909bf7c2SVarsha Kaverappa 	dst->remaining -= (intmax_t)size;
943909bf7c2SVarsha Kaverappa 	assert(dst->remaining >= 0);
944909bf7c2SVarsha Kaverappa 	if (dst->remaining < 0) {
945909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
946909bf7c2SVarsha Kaverappa 	}
947909bf7c2SVarsha Kaverappa 
948909bf7c2SVarsha Kaverappa 	memcpy(dst->cursor, src->cursor, size);
949909bf7c2SVarsha Kaverappa 	src->cursor += size;
950909bf7c2SVarsha Kaverappa 	dst->cursor += size;
951909bf7c2SVarsha Kaverappa 
952909bf7c2SVarsha Kaverappa 	return PLDM_SUCCESS;
953909bf7c2SVarsha Kaverappa }
954c63f63a2SAndrew Jeffery #ifdef __cplusplus
955c63f63a2SAndrew Jeffery }
956c63f63a2SAndrew Jeffery #endif
957c63f63a2SAndrew Jeffery 
95866c7723aSAndrew Jeffery #ifdef __cplusplus
95966c7723aSAndrew Jeffery #include <type_traits>
96066c7723aSAndrew Jeffery 
96166c7723aSAndrew Jeffery template <typename T>
96266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
96366c7723aSAndrew Jeffery 						void *buf)
96466c7723aSAndrew Jeffery {
96566c7723aSAndrew Jeffery 	static_assert(std::is_same<uint8_t *, T>::value);
96666c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint8(ctx, buf);
96766c7723aSAndrew Jeffery }
96866c7723aSAndrew Jeffery 
96966c7723aSAndrew Jeffery template <typename T>
97066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
97166c7723aSAndrew Jeffery 					       void *buf)
97266c7723aSAndrew Jeffery {
97366c7723aSAndrew Jeffery 	static_assert(std::is_same<int8_t *, T>::value);
97466c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int8(ctx, buf);
97566c7723aSAndrew Jeffery }
97666c7723aSAndrew Jeffery 
97766c7723aSAndrew Jeffery template <typename T>
97866c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
97966c7723aSAndrew Jeffery 						 void *buf)
98066c7723aSAndrew Jeffery {
98166c7723aSAndrew Jeffery 	static_assert(std::is_same<uint16_t *, T>::value);
98266c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint16(ctx, buf);
98366c7723aSAndrew Jeffery }
98466c7723aSAndrew Jeffery 
98566c7723aSAndrew Jeffery template <typename T>
98666c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
98766c7723aSAndrew Jeffery 						void *buf)
98866c7723aSAndrew Jeffery {
98966c7723aSAndrew Jeffery 	static_assert(std::is_same<int16_t *, T>::value);
99066c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int16(ctx, buf);
99166c7723aSAndrew Jeffery }
99266c7723aSAndrew Jeffery 
99366c7723aSAndrew Jeffery template <typename T>
99466c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
99566c7723aSAndrew Jeffery 						 void *buf)
99666c7723aSAndrew Jeffery {
99766c7723aSAndrew Jeffery 	static_assert(std::is_same<uint32_t *, T>::value);
99866c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint32(ctx, buf);
99966c7723aSAndrew Jeffery }
100066c7723aSAndrew Jeffery 
100166c7723aSAndrew Jeffery template <typename T>
100266c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
100366c7723aSAndrew Jeffery 						void *buf)
100466c7723aSAndrew Jeffery {
100566c7723aSAndrew Jeffery 	static_assert(std::is_same<int32_t *, T>::value);
100666c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int32(ctx, buf);
100766c7723aSAndrew Jeffery }
100866c7723aSAndrew Jeffery 
100966c7723aSAndrew Jeffery template <typename T>
101066c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
101166c7723aSAndrew Jeffery 						 void *buf)
101266c7723aSAndrew Jeffery {
101366c7723aSAndrew Jeffery 	static_assert(std::is_same<real32_t *, T>::value);
101466c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_real32(ctx, buf);
101566c7723aSAndrew Jeffery }
101666c7723aSAndrew Jeffery #endif
101766c7723aSAndrew Jeffery 
1018c63f63a2SAndrew Jeffery #endif /* BUF_H */
1019