xref: /openbmc/libpldm/src/msgbuf.h (revision 909bf7c2)
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  */
8707febdbbSAndrew Jeffery static inline int pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize,
8807febdbbSAndrew Jeffery 				   const void *buf, size_t len)
89c63f63a2SAndrew Jeffery {
90c63f63a2SAndrew Jeffery 	if (!ctx || !buf) {
91c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
92c63f63a2SAndrew Jeffery 	}
93c63f63a2SAndrew Jeffery 
942ff8cf89SAndrew Jeffery 	if ((minsize > len)) {
95c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
96c63f63a2SAndrew Jeffery 	}
97c63f63a2SAndrew Jeffery 
982ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
992ff8cf89SAndrew Jeffery 	if (len > INTMAX_MAX) {
1002ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
1012ff8cf89SAndrew Jeffery 	}
1022ff8cf89SAndrew Jeffery #endif
1032ff8cf89SAndrew Jeffery 
10407febdbbSAndrew Jeffery 	if ((uintptr_t)buf + len < len) {
105c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
106c63f63a2SAndrew Jeffery 	}
107c63f63a2SAndrew Jeffery 
108c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
1092ff8cf89SAndrew Jeffery 	ctx->remaining = (intmax_t)len;
110c63f63a2SAndrew Jeffery 
111c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
112c63f63a2SAndrew Jeffery }
113c63f63a2SAndrew Jeffery 
114c63f63a2SAndrew Jeffery /**
115c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
116c63f63a2SAndrew Jeffery  *
117c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
118c63f63a2SAndrew Jeffery  *
119c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
120c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
121c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
122c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
123c63f63a2SAndrew Jeffery  * pointer.
124c63f63a2SAndrew Jeffery  */
125c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
126c63f63a2SAndrew Jeffery {
127c63f63a2SAndrew Jeffery 	if (!ctx) {
128c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
129c63f63a2SAndrew Jeffery 	}
130c63f63a2SAndrew Jeffery 
131c63f63a2SAndrew Jeffery 	return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
132c63f63a2SAndrew Jeffery }
133c63f63a2SAndrew Jeffery 
134c63f63a2SAndrew Jeffery /**
135db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
136db7b8324SAndrew Jeffery  *
137db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
138db7b8324SAndrew Jeffery  *
139db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
140db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
141db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
142db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
143db7b8324SAndrew Jeffery  * pointer.
144db7b8324SAndrew Jeffery  */
145db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
146db7b8324SAndrew Jeffery {
147db7b8324SAndrew Jeffery 	if (!ctx) {
148db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
149db7b8324SAndrew Jeffery 	}
150db7b8324SAndrew Jeffery 
151db7b8324SAndrew Jeffery 	return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
152db7b8324SAndrew Jeffery }
153db7b8324SAndrew Jeffery 
154db7b8324SAndrew Jeffery /**
155c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
156c63f63a2SAndrew Jeffery  *
157c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
158c63f63a2SAndrew Jeffery  *
159c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
160c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
161c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
162c63f63a2SAndrew Jeffery  * bounds of the buffer.
163c63f63a2SAndrew Jeffery  */
164c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
165c63f63a2SAndrew Jeffery {
166c63f63a2SAndrew Jeffery 	int valid;
167c63f63a2SAndrew Jeffery 
168c63f63a2SAndrew Jeffery 	if (!ctx) {
169c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
170c63f63a2SAndrew Jeffery 	}
171c63f63a2SAndrew Jeffery 
172c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
173c63f63a2SAndrew Jeffery 
174c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
175c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
176c63f63a2SAndrew Jeffery 
177c63f63a2SAndrew Jeffery 	return valid;
178c63f63a2SAndrew Jeffery }
179c63f63a2SAndrew Jeffery 
180c63f63a2SAndrew Jeffery /**
181db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
182db7b8324SAndrew Jeffery  * has been completely consumed without overflow
183db7b8324SAndrew Jeffery  *
184db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
185db7b8324SAndrew Jeffery  *
186db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
187db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
188db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
189db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
190db7b8324SAndrew Jeffery  */
191db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
192db7b8324SAndrew Jeffery {
193db7b8324SAndrew Jeffery 	int consumed;
194db7b8324SAndrew Jeffery 
195db7b8324SAndrew Jeffery 	if (!ctx) {
196db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
197db7b8324SAndrew Jeffery 	}
198db7b8324SAndrew Jeffery 
199db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
200db7b8324SAndrew Jeffery 
201db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
202db7b8324SAndrew Jeffery 	ctx->remaining = 0;
203db7b8324SAndrew Jeffery 
204db7b8324SAndrew Jeffery 	return consumed;
205db7b8324SAndrew Jeffery }
206db7b8324SAndrew Jeffery 
20766c7723aSAndrew Jeffery /*
20866c7723aSAndrew Jeffery  * Exploit the pre-processor to perform type checking by macro substitution.
20966c7723aSAndrew Jeffery  *
21066c7723aSAndrew Jeffery  * A C type is defined by its alignment as well as its object
21166c7723aSAndrew Jeffery  * size, and compilers have a hammer to enforce it in the form of
21266c7723aSAndrew Jeffery  * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
21366c7723aSAndrew Jeffery  * the libpldm public API this presents a problem: Naively attempting to use the
21466c7723aSAndrew Jeffery  * msgbuf APIs on a member of a packed struct would yield an error.
21566c7723aSAndrew Jeffery  *
21666c7723aSAndrew Jeffery  * The msgbuf APIs are implemented such that data is moved through unaligned
21766c7723aSAndrew Jeffery  * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
21866c7723aSAndrew Jeffery  * make the object pointers take a trip through `void *` at its API boundary.
21966c7723aSAndrew Jeffery  * That presents a bit too much of an opportunity to non-surgically remove your
22066c7723aSAndrew Jeffery  * own foot, so here we set about doing something to mitigate that as well.
22166c7723aSAndrew Jeffery  *
22266c7723aSAndrew Jeffery  * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
22366c7723aSAndrew Jeffery  * only for the purpose of object sizes, disregarding alignment. We have a few
22466c7723aSAndrew Jeffery  * constraints that cause some headaches:
22566c7723aSAndrew Jeffery  *
22666c7723aSAndrew Jeffery  * 1. We have to perform the type-check before a call through a C function,
22766c7723aSAndrew Jeffery  *    as the function must take the object pointer argument as `void *`.
22866c7723aSAndrew Jeffery  *    Essentially, this constrains us to doing something with macros.
22966c7723aSAndrew Jeffery  *
23066c7723aSAndrew Jeffery  * 2. While libpldm is a C library, its test suite is written in C++ to take
23166c7723aSAndrew Jeffery  *    advantage of gtest.
23266c7723aSAndrew Jeffery  *
23366c7723aSAndrew Jeffery  * 3. Ideally we'd do something with C's `static_assert()`, however
23466c7723aSAndrew Jeffery  *    `static_assert()` is defined as void, and as we're constrained to macros,
23566c7723aSAndrew Jeffery  *    using `static_assert()` would require a statement-expression
23666c7723aSAndrew Jeffery  *
23766c7723aSAndrew Jeffery  * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
23866c7723aSAndrew Jeffery  *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
23966c7723aSAndrew Jeffery  *    the purpose of enabling statement-expressions in this one instance.
24066c7723aSAndrew Jeffery  *
24166c7723aSAndrew Jeffery  * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
24266c7723aSAndrew Jeffery  *    however it's implemented in terms of `_Generic()`, which is not available
24366c7723aSAndrew Jeffery  *    in C++.
24466c7723aSAndrew Jeffery  *
24566c7723aSAndrew Jeffery  * Combined this means we need separate solutions for C and C++.
24666c7723aSAndrew Jeffery  *
24766c7723aSAndrew Jeffery  * For C, as we don't have statement-expressions, we need to exploit some other
24866c7723aSAndrew Jeffery  * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
24966c7723aSAndrew Jeffery  * API function call. We also have to take care of the fact that the call-sites
25066c7723aSAndrew Jeffery  * may be in the context of a variable assignment for error-handling purposes.
25166c7723aSAndrew Jeffery  * The key observation is that we can use the comma operator as a sequence point
25266c7723aSAndrew Jeffery  * to order the type check before the API call, discarding the "result" value of
25366c7723aSAndrew Jeffery  * the type check and yielding the return value of the API call.
25466c7723aSAndrew Jeffery  *
25566c7723aSAndrew Jeffery  * C++ could be less of a headache than the C as we can leverage template
25666c7723aSAndrew Jeffery  * functions. An advantage of template functions is that while their definition
25766c7723aSAndrew Jeffery  * is driven by instantion, the definition does not appear at the source
25866c7723aSAndrew Jeffery  * location of the instantation, which gives it a great leg-up over the problems
25966c7723aSAndrew Jeffery  * we have in the C path. However, the use of the msgbuf APIs in the test suite
26066c7723aSAndrew Jeffery  * still makes things somewhat tricky, as the call-sites in the test suite are
26166c7723aSAndrew Jeffery  * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
26266c7723aSAndrew Jeffery  * takes both the object type and the required type as template arguments, and
26366c7723aSAndrew Jeffery  * then define the object pointer parameter as `void *` for a call through to
26466c7723aSAndrew Jeffery  * the appropriate msgbuf API. However, because the msgbuf API call-sites are
26566c7723aSAndrew Jeffery  * encapsulated in gtest macros, use of commas in the template specification
26666c7723aSAndrew Jeffery  * causes pre-processor confusion. In this way we're constrained to only one
26766c7723aSAndrew Jeffery  * template argument per function.
26866c7723aSAndrew Jeffery  *
26966c7723aSAndrew Jeffery  * Implement the C++ path using template functions that take the destination
27066c7723aSAndrew Jeffery  * object type as a template argument, while the name of the function symbols
27166c7723aSAndrew Jeffery  * are derived from the required type. The manual implementations of these
27266c7723aSAndrew Jeffery  * appear at the end of the header. The type safety is actually enforced
27366c7723aSAndrew Jeffery  * by `static_assert()` this time, as we can use statements as we're not
27466c7723aSAndrew Jeffery  * constrained to an expression in the templated function body.
27566c7723aSAndrew Jeffery  *
27666c7723aSAndrew Jeffery  * The invocations of pldm_msgbuf_extract_typecheck() typically result in
27766c7723aSAndrew Jeffery  * double-evaluation of some arguments. We're not yet bothered by this for two
27866c7723aSAndrew Jeffery  * reasons:
27966c7723aSAndrew Jeffery  *
28066c7723aSAndrew Jeffery  * 1. The nature of the current call-sites are such that there are no
28166c7723aSAndrew Jeffery  *    argument expressions that result in undesirable side-effects
28266c7723aSAndrew Jeffery  *
28366c7723aSAndrew Jeffery  * 2. It's an API internal to the libpldm implementation, and we can fix things
28466c7723aSAndrew Jeffery  *    whenever something crops up the violates the observation in 1.
28566c7723aSAndrew Jeffery  */
28666c7723aSAndrew Jeffery #ifdef __cplusplus
28766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
28866c7723aSAndrew Jeffery 	pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
28966c7723aSAndrew Jeffery #else
29066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
29166c7723aSAndrew Jeffery 	(pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
29266c7723aSAndrew Jeffery #endif
29366c7723aSAndrew Jeffery 
294db7b8324SAndrew Jeffery /**
295c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
296c63f63a2SAndrew Jeffery  *
297c63f63a2SAndrew Jeffery  * @param[inout] ctx - pldm_msgbuf context for extractor
298c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
299c63f63a2SAndrew Jeffery  *
300c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
301c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
302c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
303c63f63a2SAndrew Jeffery  */
30466c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint8(ctx, dst)                                    \
30566c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8,     \
30666c7723aSAndrew Jeffery 				      dst, ctx, dst)
30766c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
30866c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
309c63f63a2SAndrew Jeffery {
310c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
311c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
312c63f63a2SAndrew Jeffery 	}
313c63f63a2SAndrew Jeffery 
3142ff8cf89SAndrew Jeffery 	if (ctx->remaining == INTMAX_MIN) {
3152ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3162ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3172ff8cf89SAndrew Jeffery 	}
31866c7723aSAndrew Jeffery 	ctx->remaining -= sizeof(uint8_t);
319c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
320c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
321c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
322c63f63a2SAndrew Jeffery 	}
323c63f63a2SAndrew Jeffery 
32466c7723aSAndrew Jeffery 	memcpy(dst, ctx->cursor, sizeof(uint8_t));
32566c7723aSAndrew Jeffery 
326c63f63a2SAndrew Jeffery 	ctx->cursor++;
327c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
328c63f63a2SAndrew Jeffery }
329c63f63a2SAndrew Jeffery 
33066c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int8(ctx, dst)                                     \
33166c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst,  \
33266c7723aSAndrew Jeffery 				      ctx, dst)
33366c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
33466c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
335c63f63a2SAndrew Jeffery {
336c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
337c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
338c63f63a2SAndrew Jeffery 	}
339c63f63a2SAndrew Jeffery 
3402ff8cf89SAndrew Jeffery 	if (ctx->remaining == INTMAX_MIN) {
3412ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3422ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3432ff8cf89SAndrew Jeffery 	}
34466c7723aSAndrew Jeffery 	ctx->remaining -= sizeof(int8_t);
345c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
346c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
347c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
348c63f63a2SAndrew Jeffery 	}
349c63f63a2SAndrew Jeffery 
35066c7723aSAndrew Jeffery 	memcpy(dst, ctx->cursor, sizeof(int8_t));
351c63f63a2SAndrew Jeffery 	ctx->cursor++;
352c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
353c63f63a2SAndrew Jeffery }
354c63f63a2SAndrew Jeffery 
35566c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint16(ctx, dst)                                   \
35666c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16,   \
35766c7723aSAndrew Jeffery 				      dst, ctx, dst)
35866c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
35966c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx,
36066c7723aSAndrew Jeffery 					      void *dst)
361c63f63a2SAndrew Jeffery {
362c63f63a2SAndrew Jeffery 	uint16_t ldst;
363c63f63a2SAndrew Jeffery 
364c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
365c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
366c63f63a2SAndrew Jeffery 	}
367c63f63a2SAndrew Jeffery 
3682ff8cf89SAndrew Jeffery 	// Check for underflow while tracking the magnitude of the buffer overflow
3692ff8cf89SAndrew Jeffery 	static_assert(
3702ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
3712ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
3722ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
3732ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
3742ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
3752ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
3762ff8cf89SAndrew Jeffery 	}
3772ff8cf89SAndrew Jeffery 
378c63f63a2SAndrew Jeffery 	// Check for buffer overflow. If we overflow, account for the request as
379c63f63a2SAndrew Jeffery 	// negative values in ctx->remaining. This way we can debug how far
380c63f63a2SAndrew Jeffery 	// we've overflowed.
381c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
382c63f63a2SAndrew Jeffery 
383c63f63a2SAndrew Jeffery 	// Prevent the access if it would overflow. First, assert so we blow up
384c63f63a2SAndrew Jeffery 	// the test suite right at the point of failure. However, cater to
385c63f63a2SAndrew Jeffery 	// -DNDEBUG by explicitly testing that the access is valid.
386c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
387c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
388c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
389c63f63a2SAndrew Jeffery 	}
390c63f63a2SAndrew Jeffery 
391c63f63a2SAndrew Jeffery 	// Use memcpy() to have the compiler deal with any alignment
392c63f63a2SAndrew Jeffery 	// issues on the target architecture
393c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
394c63f63a2SAndrew Jeffery 
395c63f63a2SAndrew Jeffery 	// Only assign the target value once it's correctly decoded
39666c7723aSAndrew Jeffery 	ldst = le16toh(ldst);
39766c7723aSAndrew Jeffery 
39866c7723aSAndrew Jeffery 	// Allow storing to unaligned
39966c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
40066c7723aSAndrew Jeffery 
401c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
402c63f63a2SAndrew Jeffery 
403c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
404c63f63a2SAndrew Jeffery }
405c63f63a2SAndrew Jeffery 
40666c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int16(ctx, dst)                                    \
40766c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16,     \
40866c7723aSAndrew Jeffery 				      dst, ctx, dst)
40966c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
41066c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
411c63f63a2SAndrew Jeffery {
412c63f63a2SAndrew Jeffery 	int16_t ldst;
413c63f63a2SAndrew Jeffery 
414c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
415c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
416c63f63a2SAndrew Jeffery 	}
417c63f63a2SAndrew Jeffery 
4182ff8cf89SAndrew Jeffery 	static_assert(
4192ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4202ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4212ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
4222ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4232ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
4242ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
4252ff8cf89SAndrew Jeffery 	}
426c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
427c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
428c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
429c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
430c63f63a2SAndrew Jeffery 	}
431c63f63a2SAndrew Jeffery 
432c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
433c63f63a2SAndrew Jeffery 
43466c7723aSAndrew Jeffery 	ldst = le16toh(ldst);
43566c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
436c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
437c63f63a2SAndrew Jeffery 
438c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
439c63f63a2SAndrew Jeffery }
440c63f63a2SAndrew Jeffery 
44166c7723aSAndrew Jeffery #define pldm_msgbuf_extract_uint32(ctx, dst)                                   \
44266c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32,   \
44366c7723aSAndrew Jeffery 				      dst, ctx, dst)
44466c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
44566c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx,
44666c7723aSAndrew Jeffery 					      void *dst)
447c63f63a2SAndrew Jeffery {
448c63f63a2SAndrew Jeffery 	uint32_t ldst;
449c63f63a2SAndrew Jeffery 
450c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
451c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
452c63f63a2SAndrew Jeffery 	}
453c63f63a2SAndrew Jeffery 
4542ff8cf89SAndrew Jeffery 	static_assert(
4552ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4562ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4572ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
4582ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4592ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
4602ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
4612ff8cf89SAndrew Jeffery 	}
462c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
463c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
464c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
465c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
466c63f63a2SAndrew Jeffery 	}
467c63f63a2SAndrew Jeffery 
468c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
469c63f63a2SAndrew Jeffery 
47066c7723aSAndrew Jeffery 	ldst = le32toh(ldst);
47166c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
472c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
473c63f63a2SAndrew Jeffery 
474c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
475c63f63a2SAndrew Jeffery }
476c63f63a2SAndrew Jeffery 
47766c7723aSAndrew Jeffery #define pldm_msgbuf_extract_int32(ctx, dst)                                    \
47866c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32,     \
47966c7723aSAndrew Jeffery 				      dst, ctx, dst)
48066c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
48166c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
482c63f63a2SAndrew Jeffery {
483c63f63a2SAndrew Jeffery 	int32_t ldst;
484c63f63a2SAndrew Jeffery 
485c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
486c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
487c63f63a2SAndrew Jeffery 	}
488c63f63a2SAndrew Jeffery 
4892ff8cf89SAndrew Jeffery 	static_assert(
4902ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
4912ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
4922ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
4932ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
4942ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
4952ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
4962ff8cf89SAndrew Jeffery 	}
497c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
498c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
499c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
500c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
501c63f63a2SAndrew Jeffery 	}
502c63f63a2SAndrew Jeffery 
503c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
504c63f63a2SAndrew Jeffery 
50566c7723aSAndrew Jeffery 	ldst = le32toh(ldst);
50666c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
507c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
508c63f63a2SAndrew Jeffery 
509c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
510c63f63a2SAndrew Jeffery }
511c63f63a2SAndrew Jeffery 
51266c7723aSAndrew Jeffery #define pldm_msgbuf_extract_real32(ctx, dst)                                   \
51366c7723aSAndrew Jeffery 	pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32,   \
51466c7723aSAndrew Jeffery 				      dst, ctx, dst)
51566c7723aSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
51666c7723aSAndrew Jeffery static inline int pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx,
51766c7723aSAndrew Jeffery 					      void *dst)
518c63f63a2SAndrew Jeffery {
519c63f63a2SAndrew Jeffery 	uint32_t ldst;
520c63f63a2SAndrew Jeffery 
52166c7723aSAndrew Jeffery 	_Static_assert(sizeof(real32_t) == sizeof(ldst),
52266c7723aSAndrew Jeffery 		       "Mismatched type sizes for dst and ldst");
52366c7723aSAndrew Jeffery 
524c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
525c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
526c63f63a2SAndrew Jeffery 	}
527c63f63a2SAndrew Jeffery 
5282ff8cf89SAndrew Jeffery 	static_assert(
5292ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
5302ff8cf89SAndrew Jeffery 		sizeof(ldst) < INTMAX_MAX,
5312ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
5322ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
5332ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
5342ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
5352ff8cf89SAndrew Jeffery 	}
536c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
537c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
538c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
539c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
540c63f63a2SAndrew Jeffery 	}
541c63f63a2SAndrew Jeffery 
542c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
543c63f63a2SAndrew Jeffery 	ldst = le32toh(ldst);
54466c7723aSAndrew Jeffery 	memcpy(dst, &ldst, sizeof(ldst));
54566c7723aSAndrew Jeffery 	ctx->cursor += sizeof(ldst);
546c63f63a2SAndrew Jeffery 
547c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
548c63f63a2SAndrew Jeffery }
549c63f63a2SAndrew Jeffery 
55066c7723aSAndrew Jeffery /**
55166c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the lvalue named by dst.
55266c7723aSAndrew Jeffery  *
55366c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
55466c7723aSAndrew Jeffery  * @param dst The lvalue into which the field at the msgbuf cursor should be
55566c7723aSAndrew Jeffery  *            extracted
55666c7723aSAndrew Jeffery  *
55766c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
55866c7723aSAndrew Jeffery  */
559c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
56066c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
56166c7723aSAndrew Jeffery 		uint8_t: pldm__msgbuf_extract_uint8,                           \
56266c7723aSAndrew Jeffery 		int8_t: pldm__msgbuf_extract_int8,                             \
56366c7723aSAndrew Jeffery 		uint16_t: pldm__msgbuf_extract_uint16,                         \
56466c7723aSAndrew Jeffery 		int16_t: pldm__msgbuf_extract_int16,                           \
56566c7723aSAndrew Jeffery 		uint32_t: pldm__msgbuf_extract_uint32,                         \
56666c7723aSAndrew Jeffery 		int32_t: pldm__msgbuf_extract_int32,                           \
56766c7723aSAndrew Jeffery 		real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
56866c7723aSAndrew Jeffery 
56966c7723aSAndrew Jeffery /**
57066c7723aSAndrew Jeffery  * Extract the field at the msgbuf cursor into the object pointed-to by dst.
57166c7723aSAndrew Jeffery  *
57266c7723aSAndrew Jeffery  * @param ctx The msgbuf context object
57366c7723aSAndrew Jeffery  * @param dst The pointer to the object into which the field at the msgbuf
57466c7723aSAndrew Jeffery  *            cursor should be extracted
57566c7723aSAndrew Jeffery  *
57666c7723aSAndrew Jeffery  * @return PLDM_SUCCESS on success, otherwise another value on error
57766c7723aSAndrew Jeffery  */
57866c7723aSAndrew Jeffery #define pldm_msgbuf_extract_p(ctx, dst)                                        \
57966c7723aSAndrew Jeffery 	_Generic((dst),                                                        \
58066c7723aSAndrew Jeffery 		uint8_t *: pldm__msgbuf_extract_uint8,                         \
58166c7723aSAndrew Jeffery 		int8_t *: pldm__msgbuf_extract_int8,                           \
58266c7723aSAndrew Jeffery 		uint16_t *: pldm__msgbuf_extract_uint16,                       \
58366c7723aSAndrew Jeffery 		int16_t *: pldm__msgbuf_extract_int16,                         \
58466c7723aSAndrew Jeffery 		uint32_t *: pldm__msgbuf_extract_uint32,                       \
58566c7723aSAndrew Jeffery 		int32_t *: pldm__msgbuf_extract_int32,                         \
58666c7723aSAndrew Jeffery 		real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
587c63f63a2SAndrew Jeffery 
588369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx,
589369b121aSAndrew Jeffery 						  uint8_t *dst, size_t count)
590369b121aSAndrew Jeffery {
591369b121aSAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
592369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
593369b121aSAndrew Jeffery 	}
594369b121aSAndrew Jeffery 
595369b121aSAndrew Jeffery 	if (!count) {
596369b121aSAndrew Jeffery 		return PLDM_SUCCESS;
597369b121aSAndrew Jeffery 	}
598369b121aSAndrew Jeffery 
5992ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
6002ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
601369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
602369b121aSAndrew Jeffery 	}
6032ff8cf89SAndrew Jeffery #endif
604369b121aSAndrew Jeffery 
6052ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
6062ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6072ff8cf89SAndrew Jeffery 	}
6082ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)count;
609369b121aSAndrew Jeffery 	assert(ctx->remaining >= 0);
610369b121aSAndrew Jeffery 	if (ctx->remaining < 0) {
611369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
612369b121aSAndrew Jeffery 	}
613369b121aSAndrew Jeffery 
614a065eccbSAndrew Jeffery 	memcpy(dst, ctx->cursor, count);
615a065eccbSAndrew Jeffery 	ctx->cursor += count;
616369b121aSAndrew Jeffery 
617369b121aSAndrew Jeffery 	return PLDM_SUCCESS;
618369b121aSAndrew Jeffery }
619369b121aSAndrew Jeffery 
620369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
62137dd6a3dSAndrew Jeffery 	_Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
62237dd6a3dSAndrew Jeffery 								     count)
623369b121aSAndrew Jeffery 
624062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
625062c8762SThu Nguyen 					    const uint32_t src)
626062c8762SThu Nguyen {
627062c8762SThu Nguyen 	uint32_t val = htole32(src);
628062c8762SThu Nguyen 
629062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
630062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
631062c8762SThu Nguyen 	}
632062c8762SThu Nguyen 
6332ff8cf89SAndrew Jeffery 	static_assert(
6342ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
6352ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
6362ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
6372ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
6382ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
6392ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6402ff8cf89SAndrew Jeffery 	}
641062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
642062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
643062c8762SThu Nguyen 	if (ctx->remaining < 0) {
644062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
645062c8762SThu Nguyen 	}
646062c8762SThu Nguyen 
647062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
648062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
649062c8762SThu Nguyen 
650062c8762SThu Nguyen 	return PLDM_SUCCESS;
651062c8762SThu Nguyen }
652062c8762SThu Nguyen 
653062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
654062c8762SThu Nguyen 					    const uint16_t src)
655062c8762SThu Nguyen {
656062c8762SThu Nguyen 	uint16_t val = htole16(src);
657062c8762SThu Nguyen 
658062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
659062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
660062c8762SThu Nguyen 	}
661062c8762SThu Nguyen 
6622ff8cf89SAndrew Jeffery 	static_assert(
6632ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
6642ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
6652ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
6662ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
6672ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
6682ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6692ff8cf89SAndrew Jeffery 	}
670062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
671062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
672062c8762SThu Nguyen 	if (ctx->remaining < 0) {
673062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
674062c8762SThu Nguyen 	}
675062c8762SThu Nguyen 
676062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
677062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
678062c8762SThu Nguyen 
679062c8762SThu Nguyen 	return PLDM_SUCCESS;
680062c8762SThu Nguyen }
681062c8762SThu Nguyen 
682062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
683062c8762SThu Nguyen 					   const uint8_t src)
684062c8762SThu Nguyen {
685062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
686062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
687062c8762SThu Nguyen 	}
688062c8762SThu Nguyen 
6892ff8cf89SAndrew Jeffery 	static_assert(
6902ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
6912ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
6922ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
6932ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
6942ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
6952ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
6962ff8cf89SAndrew Jeffery 	}
697062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
698062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
699062c8762SThu Nguyen 	if (ctx->remaining < 0) {
700062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
701062c8762SThu Nguyen 	}
702062c8762SThu Nguyen 
703062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
704062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
705062c8762SThu Nguyen 
706062c8762SThu Nguyen 	return PLDM_SUCCESS;
707062c8762SThu Nguyen }
708062c8762SThu Nguyen 
709062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
710062c8762SThu Nguyen 					   const int32_t src)
711062c8762SThu Nguyen {
712062c8762SThu Nguyen 	int32_t val = htole32(src);
713062c8762SThu Nguyen 
714062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
715062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
716062c8762SThu Nguyen 	}
717062c8762SThu Nguyen 
7182ff8cf89SAndrew Jeffery 	static_assert(
7192ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7202ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7212ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
7222ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7232ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7242ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7252ff8cf89SAndrew Jeffery 	}
726062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
727062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
728062c8762SThu Nguyen 	if (ctx->remaining < 0) {
729062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
730062c8762SThu Nguyen 	}
731062c8762SThu Nguyen 
732062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
733062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
734062c8762SThu Nguyen 
735062c8762SThu Nguyen 	return PLDM_SUCCESS;
736062c8762SThu Nguyen }
737062c8762SThu Nguyen 
738062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
739062c8762SThu Nguyen 					   const int16_t src)
740062c8762SThu Nguyen {
741062c8762SThu Nguyen 	int16_t val = htole16(src);
742062c8762SThu Nguyen 
743062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
744062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
745062c8762SThu Nguyen 	}
746062c8762SThu Nguyen 
7472ff8cf89SAndrew Jeffery 	static_assert(
7482ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7492ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7502ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
7512ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7522ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7532ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7542ff8cf89SAndrew Jeffery 	}
755062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
756062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
757062c8762SThu Nguyen 	if (ctx->remaining < 0) {
758062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
759062c8762SThu Nguyen 	}
760062c8762SThu Nguyen 
761062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
762062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
763062c8762SThu Nguyen 
764062c8762SThu Nguyen 	return PLDM_SUCCESS;
765062c8762SThu Nguyen }
766062c8762SThu Nguyen 
767062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
768062c8762SThu Nguyen 					  const int8_t src)
769062c8762SThu Nguyen {
770062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
771062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
772062c8762SThu Nguyen 	}
773062c8762SThu Nguyen 
7742ff8cf89SAndrew Jeffery 	static_assert(
7752ff8cf89SAndrew Jeffery 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
7762ff8cf89SAndrew Jeffery 		sizeof(src) < INTMAX_MAX,
7772ff8cf89SAndrew Jeffery 		"The following addition may not uphold the runtime assertion");
7782ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
7792ff8cf89SAndrew Jeffery 		assert(ctx->remaining < 0);
7802ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7812ff8cf89SAndrew Jeffery 	}
782062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
783062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
784062c8762SThu Nguyen 	if (ctx->remaining < 0) {
785062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
786062c8762SThu Nguyen 	}
787062c8762SThu Nguyen 
788062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
789062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
790062c8762SThu Nguyen 
791062c8762SThu Nguyen 	return PLDM_SUCCESS;
792062c8762SThu Nguyen }
793062c8762SThu Nguyen 
794062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
79537dd6a3dSAndrew Jeffery 	_Generic((src),                                                        \
79637dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_uint8,                             \
79737dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_insert_int8,                               \
79837dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_insert_uint16,                           \
79937dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_insert_int16,                             \
80037dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_insert_uint32,                           \
80137dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_insert_int32)(dst, src)
802062c8762SThu Nguyen 
803062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx,
804062c8762SThu Nguyen 						 const uint8_t *src,
805062c8762SThu Nguyen 						 size_t count)
806062c8762SThu Nguyen {
807062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !src) {
808062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
809062c8762SThu Nguyen 	}
810062c8762SThu Nguyen 
811062c8762SThu Nguyen 	if (!count) {
812062c8762SThu Nguyen 		return PLDM_SUCCESS;
813062c8762SThu Nguyen 	}
814062c8762SThu Nguyen 
8152ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
8162ff8cf89SAndrew Jeffery 	if (count > INTMAX_MAX) {
817062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
818062c8762SThu Nguyen 	}
8192ff8cf89SAndrew Jeffery #endif
820062c8762SThu Nguyen 
8212ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
8222ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
8232ff8cf89SAndrew Jeffery 	}
8242ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)count;
825062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
826062c8762SThu Nguyen 	if (ctx->remaining < 0) {
827062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
828062c8762SThu Nguyen 	}
829062c8762SThu Nguyen 
830a065eccbSAndrew Jeffery 	memcpy(ctx->cursor, src, count);
831a065eccbSAndrew Jeffery 	ctx->cursor += count;
832062c8762SThu Nguyen 
833062c8762SThu Nguyen 	return PLDM_SUCCESS;
834062c8762SThu Nguyen }
835062c8762SThu Nguyen 
836062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count)                              \
83737dd6a3dSAndrew Jeffery 	_Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src,  \
83837dd6a3dSAndrew Jeffery 								    count)
839062c8762SThu Nguyen 
840062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
841062c8762SThu Nguyen 					    size_t required, void **cursor)
842062c8762SThu Nguyen {
843062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor) {
844062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
845062c8762SThu Nguyen 	}
846062c8762SThu Nguyen 
8472ff8cf89SAndrew Jeffery #if INTMAX_MAX < SIZE_MAX
8482ff8cf89SAndrew Jeffery 	if (required > INTMAX_MAX) {
849062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
850062c8762SThu Nguyen 	}
8512ff8cf89SAndrew Jeffery #endif
852062c8762SThu Nguyen 
8532ff8cf89SAndrew Jeffery 	if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
8542ff8cf89SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
8552ff8cf89SAndrew Jeffery 	}
8562ff8cf89SAndrew Jeffery 	ctx->remaining -= (intmax_t)required;
857062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
858062c8762SThu Nguyen 	if (ctx->remaining < 0) {
859062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
860062c8762SThu Nguyen 	}
861062c8762SThu Nguyen 
862062c8762SThu Nguyen 	*cursor = ctx->cursor;
863062c8762SThu Nguyen 	ctx->cursor += required;
864062c8762SThu Nguyen 
865062c8762SThu Nguyen 	return PLDM_SUCCESS;
866062c8762SThu Nguyen }
867062c8762SThu Nguyen 
868062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx,
869062c8762SThu Nguyen 					     void **cursor, size_t *len)
870062c8762SThu Nguyen {
871062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
872062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
873062c8762SThu Nguyen 	}
874062c8762SThu Nguyen 
875062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
876062c8762SThu Nguyen 	if (ctx->remaining < 0) {
877062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
878062c8762SThu Nguyen 	}
879062c8762SThu Nguyen 
880062c8762SThu Nguyen 	*cursor = ctx->cursor;
881062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
882062c8762SThu Nguyen 	*len = ctx->remaining;
883062c8762SThu Nguyen 	ctx->remaining = 0;
884062c8762SThu Nguyen 
885062c8762SThu Nguyen 	return PLDM_SUCCESS;
886062c8762SThu Nguyen }
887*909bf7c2SVarsha Kaverappa 
888*909bf7c2SVarsha Kaverappa /**
889*909bf7c2SVarsha Kaverappa  * @brief pldm_msgbuf copy data between two msg buffers
890*909bf7c2SVarsha Kaverappa  *
891*909bf7c2SVarsha Kaverappa  * @param[inout] src - pldm_msgbuf for source from where value should be copied
892*909bf7c2SVarsha Kaverappa  * @param[inout] dst - destination of copy from source
893*909bf7c2SVarsha Kaverappa  * @param[in] size - size of data to be copied
894*909bf7c2SVarsha Kaverappa  * @param[in] description - description of data copied
895*909bf7c2SVarsha Kaverappa  *
896*909bf7c2SVarsha Kaverappa  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
897*909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_LENGTH otherwise.
898*909bf7c2SVarsha Kaverappa  * PLDM_ERROR_INVALID_DATA if input is invalid
899*909bf7c2SVarsha Kaverappa  */
900*909bf7c2SVarsha Kaverappa #define pldm_msgbuf_copy(dst, src, type, name)                                 \
901*909bf7c2SVarsha Kaverappa 	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
902*909bf7c2SVarsha Kaverappa // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
903*909bf7c2SVarsha Kaverappa static inline int pldm__msgbuf_copy(struct pldm_msgbuf *dst,
904*909bf7c2SVarsha Kaverappa 				    struct pldm_msgbuf *src, size_t size,
905*909bf7c2SVarsha Kaverappa 				    const char *description)
906*909bf7c2SVarsha Kaverappa {
907*909bf7c2SVarsha Kaverappa 	if (!src || !src->cursor || !dst || !dst->cursor || !description) {
908*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_DATA;
909*909bf7c2SVarsha Kaverappa 	}
910*909bf7c2SVarsha Kaverappa 
911*909bf7c2SVarsha Kaverappa #if INTMAX_MAX < SIZE_MAX
912*909bf7c2SVarsha Kaverappa 	if (size > INTMAX_MAX) {
913*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
914*909bf7c2SVarsha Kaverappa 	}
915*909bf7c2SVarsha Kaverappa #endif
916*909bf7c2SVarsha Kaverappa 
917*909bf7c2SVarsha Kaverappa 	if (src->remaining < INTMAX_MIN + (intmax_t)size) {
918*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
919*909bf7c2SVarsha Kaverappa 	}
920*909bf7c2SVarsha Kaverappa 
921*909bf7c2SVarsha Kaverappa 	if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
922*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
923*909bf7c2SVarsha Kaverappa 	}
924*909bf7c2SVarsha Kaverappa 
925*909bf7c2SVarsha Kaverappa 	src->remaining -= (intmax_t)size;
926*909bf7c2SVarsha Kaverappa 	assert(src->remaining >= 0);
927*909bf7c2SVarsha Kaverappa 	if (src->remaining < 0) {
928*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
929*909bf7c2SVarsha Kaverappa 	}
930*909bf7c2SVarsha Kaverappa 
931*909bf7c2SVarsha Kaverappa 	dst->remaining -= (intmax_t)size;
932*909bf7c2SVarsha Kaverappa 	assert(dst->remaining >= 0);
933*909bf7c2SVarsha Kaverappa 	if (dst->remaining < 0) {
934*909bf7c2SVarsha Kaverappa 		return PLDM_ERROR_INVALID_LENGTH;
935*909bf7c2SVarsha Kaverappa 	}
936*909bf7c2SVarsha Kaverappa 
937*909bf7c2SVarsha Kaverappa 	memcpy(dst->cursor, src->cursor, size);
938*909bf7c2SVarsha Kaverappa 	src->cursor += size;
939*909bf7c2SVarsha Kaverappa 	dst->cursor += size;
940*909bf7c2SVarsha Kaverappa 
941*909bf7c2SVarsha Kaverappa 	return PLDM_SUCCESS;
942*909bf7c2SVarsha Kaverappa }
943c63f63a2SAndrew Jeffery #ifdef __cplusplus
944c63f63a2SAndrew Jeffery }
945c63f63a2SAndrew Jeffery #endif
946c63f63a2SAndrew Jeffery 
94766c7723aSAndrew Jeffery #ifdef __cplusplus
94866c7723aSAndrew Jeffery #include <type_traits>
94966c7723aSAndrew Jeffery 
95066c7723aSAndrew Jeffery template <typename T>
95166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
95266c7723aSAndrew Jeffery 						void *buf)
95366c7723aSAndrew Jeffery {
95466c7723aSAndrew Jeffery 	static_assert(std::is_same<uint8_t *, T>::value);
95566c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint8(ctx, buf);
95666c7723aSAndrew Jeffery }
95766c7723aSAndrew Jeffery 
95866c7723aSAndrew Jeffery template <typename T>
95966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
96066c7723aSAndrew Jeffery 					       void *buf)
96166c7723aSAndrew Jeffery {
96266c7723aSAndrew Jeffery 	static_assert(std::is_same<int8_t *, T>::value);
96366c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int8(ctx, buf);
96466c7723aSAndrew Jeffery }
96566c7723aSAndrew Jeffery 
96666c7723aSAndrew Jeffery template <typename T>
96766c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
96866c7723aSAndrew Jeffery 						 void *buf)
96966c7723aSAndrew Jeffery {
97066c7723aSAndrew Jeffery 	static_assert(std::is_same<uint16_t *, T>::value);
97166c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint16(ctx, buf);
97266c7723aSAndrew Jeffery }
97366c7723aSAndrew Jeffery 
97466c7723aSAndrew Jeffery template <typename T>
97566c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
97666c7723aSAndrew Jeffery 						void *buf)
97766c7723aSAndrew Jeffery {
97866c7723aSAndrew Jeffery 	static_assert(std::is_same<int16_t *, T>::value);
97966c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int16(ctx, buf);
98066c7723aSAndrew Jeffery }
98166c7723aSAndrew Jeffery 
98266c7723aSAndrew Jeffery template <typename T>
98366c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
98466c7723aSAndrew Jeffery 						 void *buf)
98566c7723aSAndrew Jeffery {
98666c7723aSAndrew Jeffery 	static_assert(std::is_same<uint32_t *, T>::value);
98766c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_uint32(ctx, buf);
98866c7723aSAndrew Jeffery }
98966c7723aSAndrew Jeffery 
99066c7723aSAndrew Jeffery template <typename T>
99166c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
99266c7723aSAndrew Jeffery 						void *buf)
99366c7723aSAndrew Jeffery {
99466c7723aSAndrew Jeffery 	static_assert(std::is_same<int32_t *, T>::value);
99566c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_int32(ctx, buf);
99666c7723aSAndrew Jeffery }
99766c7723aSAndrew Jeffery 
99866c7723aSAndrew Jeffery template <typename T>
99966c7723aSAndrew Jeffery static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
100066c7723aSAndrew Jeffery 						 void *buf)
100166c7723aSAndrew Jeffery {
100266c7723aSAndrew Jeffery 	static_assert(std::is_same<real32_t *, T>::value);
100366c7723aSAndrew Jeffery 	return pldm__msgbuf_extract_real32(ctx, buf);
100466c7723aSAndrew Jeffery }
100566c7723aSAndrew Jeffery #endif
100666c7723aSAndrew Jeffery 
1007c63f63a2SAndrew Jeffery #endif /* BUF_H */
1008