blob: cf30bad5ca1684a079a64637fd72f9b9be31b44a [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10302#ifndef PLDM_MSGBUF_H
3#define PLDM_MSGBUF_H
4
Andrew Jeffery860a43d2024-08-23 01:21:58 +00005#include "compiler.h"
6
Andrew Jeffery66c77232024-04-24 11:42:02 +09307/*
8 * Historically, many of the structs exposed in libpldm's public headers are
9 * defined with __attribute__((packed)). This is unfortunate: it gives the
10 * impression that a wire-format buffer can be cast to the message type to make
11 * the message's fields easily accessible. As it turns out, that's not
12 * that's valid for several reasons:
13 *
14 * 1. Casting the wire-format buffer to a struct of the message type doesn't
15 * abstract the endianness of message field values
16 *
17 * 2. Some messages contain packed tagged union fields which cannot be properly
18 * described in a C struct.
19 *
20 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
21 * that is type-safe, spatially memory-safe, endian-safe, performant, and
22 * free of undefined-behaviour. Message structs that are added to the public
23 * library API should no-longer be marked __attribute__((packed)), and the
24 * implementation of their encode and decode functions must exploit the msgbuf
25 * API.
26 *
27 * However, we would like to allow implementation of codec functions in terms of
28 * msgbuf APIs even if they're decoding a message into a (historically) packed
29 * struct. Some of the complexity that follows is a consequence of the packed/
30 * unpacked conflict.
31 */
32
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103033#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093034/*
35 * Fix up C11's _Static_assert() vs C++'s static_assert().
36 *
37 * Can we please have nice things for once.
38 */
39// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
40#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103041extern "C" {
42#endif
43
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103044#include <libpldm/base.h>
45#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103046
Andrew Jeffery66c77232024-04-24 11:42:02 +093047#include "compiler.h"
48
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103049#include <assert.h>
50#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093051#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103052#include <limits.h>
53#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093054#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103055#include <string.h>
56#include <sys/types.h>
Thu Nguyen15237782024-07-02 09:30:41 +000057#include <uchar.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103058
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093059/*
60 * We can't use static_assert() outside of some other C construct. Deal
61 * with high-level global assertions by burying them in an unused struct
62 * declaration, that has a sole member for compliance with the requirement that
63 * types must have a size.
64*/
65static struct {
66 static_assert(
67 INTMAX_MAX != SIZE_MAX,
68 "Extraction and insertion value comparisons may be broken");
69 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
70 "Extraction and insertion arithmetic may be broken");
71 int compliance;
Andrew Jeffery860a43d2024-08-23 01:21:58 +000072} build_assertions LIBPLDM_CC_UNUSED;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093073
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103074struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070075 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093076 intmax_t remaining;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103077};
78
Andrew Jefferyd861a682024-06-03 21:43:09 +093079/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103080 * @brief Initialize pldm buf struct for buf extractor
81 *
82 * @param[out] ctx - pldm_msgbuf context for extractor
83 * @param[in] minsize - The minimum required length of buffer `buf`
84 * @param[in] buf - buffer to be extracted
85 * @param[in] len - size of buffer
86 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093087 * @return 0 on success, otherwise an error code appropriate for the current
88 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103089 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +030090LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +103091LIBPLDM_CC_ALWAYS_INLINE
92LIBPLDM_CC_WARN_UNUSED_RESULT
93int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093094// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093095pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
96 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103097{
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093098 if ((minsize > len)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093099 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030100 }
101
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930102#if INTMAX_MAX < SIZE_MAX
103 if (len > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930104 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930105 }
106#endif
107
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930108 if (UINTPTR_MAX - (uintptr_t)buf < len) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930109 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030110 }
111
112 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930113 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030114
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930115 return 0;
116}
117
118/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030119 * @brief Validate buffer overflow state
120 *
121 * @param[in] ctx - pldm_msgbuf context for extractor
122 *
123 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
124 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
125 * prior accesses would have occurred beyond the bounds of the buffer, and
126 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
127 * pointer.
128 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300129LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030130LIBPLDM_CC_ALWAYS_INLINE
131LIBPLDM_CC_WARN_UNUSED_RESULT
132int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030133{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930134 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930135 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030136 }
137
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930138 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030139}
140
141/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930142 * @brief Test whether a message buffer has been exactly consumed
143 *
144 * @param[in] ctx - pldm_msgbuf context for extractor
145 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030146 * @return 0 iff there are zero bytes of data that remain unread from the buffer
Andrew Jeffery63b5a662025-03-05 13:26:12 +1030147 * and no overflow has occurred. Otherwise, -EBADMSG if the buffer has not been
148 * completely consumed, or -EOVERFLOW if accesses were attempted beyond the
149 * bounds of the buffer.
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930150 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300151LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030152LIBPLDM_CC_ALWAYS_INLINE
153LIBPLDM_CC_WARN_UNUSED_RESULT
154int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930155{
Andrew Jeffery63b5a662025-03-05 13:26:12 +1030156 if (ctx->remaining > 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930157 return -EBADMSG;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930158 }
159
Andrew Jeffery63b5a662025-03-05 13:26:12 +1030160 if (ctx->remaining < 0) {
161 return -EOVERFLOW;
162 }
163
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930164 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930165}
166
167/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030168 * @brief Complete the pldm_msgbuf instance
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030169 *
170 * @param[in] ctx - pldm_msgbuf context for extractor
171 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030172 * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030173 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300174LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030175LIBPLDM_CC_ALWAYS_INLINE
176LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030177int pldm_msgbuf_complete(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030178{
179 int valid;
180
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030181 valid = pldm_msgbuf_validate(ctx);
182
183 ctx->cursor = NULL;
184 ctx->remaining = 0;
185
186 return valid;
187}
188
189/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030190 * @brief Complete the pldm_msgbuf instance, and check that the underlying buffer
191 * has been entirely consumed without overflow
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930192 *
193 * @param[in] ctx - pldm_msgbuf context
194 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030195 * @return 0 if all buffer access were in-bounds and completely consume the
Andrew Jeffery63b5a662025-03-05 13:26:12 +1030196 * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
197 * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
198 * buffer.
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930199 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300200LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030201LIBPLDM_CC_ALWAYS_INLINE
202LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030203int pldm_msgbuf_complete_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930204{
205 int consumed;
206
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930207 consumed = pldm_msgbuf_consumed(ctx);
208
209 ctx->cursor = NULL;
210 ctx->remaining = 0;
211
212 return consumed;
213}
214
Andrew Jeffery66c77232024-04-24 11:42:02 +0930215/*
216 * Exploit the pre-processor to perform type checking by macro substitution.
217 *
218 * A C type is defined by its alignment as well as its object
219 * size, and compilers have a hammer to enforce it in the form of
220 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
221 * the libpldm public API this presents a problem: Naively attempting to use the
222 * msgbuf APIs on a member of a packed struct would yield an error.
223 *
224 * The msgbuf APIs are implemented such that data is moved through unaligned
225 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
226 * make the object pointers take a trip through `void *` at its API boundary.
227 * That presents a bit too much of an opportunity to non-surgically remove your
228 * own foot, so here we set about doing something to mitigate that as well.
229 *
230 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
231 * only for the purpose of object sizes, disregarding alignment. We have a few
232 * constraints that cause some headaches:
233 *
234 * 1. We have to perform the type-check before a call through a C function,
235 * as the function must take the object pointer argument as `void *`.
236 * Essentially, this constrains us to doing something with macros.
237 *
238 * 2. While libpldm is a C library, its test suite is written in C++ to take
239 * advantage of gtest.
240 *
241 * 3. Ideally we'd do something with C's `static_assert()`, however
242 * `static_assert()` is defined as void, and as we're constrained to macros,
243 * using `static_assert()` would require a statement-expression
244 *
245 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
246 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
247 * the purpose of enabling statement-expressions in this one instance.
248 *
249 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
250 * however it's implemented in terms of `_Generic()`, which is not available
251 * in C++.
252 *
253 * Combined this means we need separate solutions for C and C++.
254 *
255 * For C, as we don't have statement-expressions, we need to exploit some other
256 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
257 * API function call. We also have to take care of the fact that the call-sites
258 * may be in the context of a variable assignment for error-handling purposes.
259 * The key observation is that we can use the comma operator as a sequence point
260 * to order the type check before the API call, discarding the "result" value of
261 * the type check and yielding the return value of the API call.
262 *
263 * C++ could be less of a headache than the C as we can leverage template
264 * functions. An advantage of template functions is that while their definition
265 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530266 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930267 * we have in the C path. However, the use of the msgbuf APIs in the test suite
268 * still makes things somewhat tricky, as the call-sites in the test suite are
269 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
270 * takes both the object type and the required type as template arguments, and
271 * then define the object pointer parameter as `void *` for a call through to
272 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
273 * encapsulated in gtest macros, use of commas in the template specification
274 * causes pre-processor confusion. In this way we're constrained to only one
275 * template argument per function.
276 *
277 * Implement the C++ path using template functions that take the destination
278 * object type as a template argument, while the name of the function symbols
279 * are derived from the required type. The manual implementations of these
280 * appear at the end of the header. The type safety is actually enforced
281 * by `static_assert()` this time, as we can use statements as we're not
282 * constrained to an expression in the templated function body.
283 *
284 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
285 * double-evaluation of some arguments. We're not yet bothered by this for two
286 * reasons:
287 *
288 * 1. The nature of the current call-sites are such that there are no
289 * argument expressions that result in undesirable side-effects
290 *
291 * 2. It's an API internal to the libpldm implementation, and we can fix things
292 * whenever something crops up the violates the observation in 1.
293 */
294#ifdef __cplusplus
295#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
296 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
297#else
298#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
299 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
300#endif
301
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930302/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030303 * @brief pldm_msgbuf extractor for a uint8_t
304 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530305 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030306 * @param[out] dst - destination of extracted value
307 *
308 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
309 * PLDM_ERROR_INVALID_LENGTH otherwise.
310 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
311 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930312#define pldm_msgbuf_extract_uint8(ctx, dst) \
313 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930314 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300315LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300316LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930317// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930318pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030319{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300320 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930321 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030322 }
323
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930324 if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
325 memcpy(dst, ctx->cursor, sizeof(uint8_t));
326 ctx->cursor++;
327 ctx->remaining -= sizeof(uint8_t);
328 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030329 }
330
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930331 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
332 ctx->remaining -= sizeof(uint8_t);
333 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930334
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930335 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030336}
337
Andrew Jeffery66c77232024-04-24 11:42:02 +0930338#define pldm_msgbuf_extract_int8(ctx, dst) \
339 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930340 ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300341LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300342LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930343// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930344pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030345{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300346 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930347 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030348 }
349
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930350 if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
351 memcpy(dst, ctx->cursor, sizeof(int8_t));
352 ctx->cursor++;
353 ctx->remaining -= sizeof(int8_t);
354 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030355 }
356
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930357 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
358 ctx->remaining -= sizeof(int8_t);
359 }
360
361 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030362}
363
Andrew Jeffery66c77232024-04-24 11:42:02 +0930364#define pldm_msgbuf_extract_uint16(ctx, dst) \
365 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930366 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300367LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300368LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930369// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930370pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030371{
372 uint16_t ldst;
373
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300374 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930375 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030376 }
377
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930378 // Check for underflow while tracking the magnitude of the buffer overflow
379 static_assert(
380 // NOLINTNEXTLINE(bugprone-sizeof-expression)
381 sizeof(ldst) < INTMAX_MAX,
382 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930383
384 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
385 // Use memcpy() to have the compiler deal with any alignment
386 // issues on the target architecture
387 memcpy(&ldst, ctx->cursor, sizeof(ldst));
388
389 // Only assign the target value once it's correctly decoded
390 ldst = le16toh(ldst);
391
392 // Allow storing to unaligned
393 memcpy(dst, &ldst, sizeof(ldst));
394
395 ctx->cursor += sizeof(ldst);
396 ctx->remaining -= sizeof(ldst);
397 return 0;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930398 }
399
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930400 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
401 ctx->remaining -= sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030402 }
403
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930404 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030405}
406
Andrew Jeffery66c77232024-04-24 11:42:02 +0930407#define pldm_msgbuf_extract_int16(ctx, dst) \
408 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930409 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300410LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300411LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930412// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930413pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030414{
415 int16_t ldst;
416
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300417 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930418 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030419 }
420
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930421 static_assert(
422 // NOLINTNEXTLINE(bugprone-sizeof-expression)
423 sizeof(ldst) < INTMAX_MAX,
424 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930425
426 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
427 memcpy(&ldst, ctx->cursor, sizeof(ldst));
428 ldst = le16toh(ldst);
429 memcpy(dst, &ldst, sizeof(ldst));
430 ctx->cursor += sizeof(ldst);
431 ctx->remaining -= sizeof(ldst);
432 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030433 }
434
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930435 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
436 ctx->remaining -= sizeof(ldst);
437 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030438
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930439 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030440}
441
Andrew Jeffery66c77232024-04-24 11:42:02 +0930442#define pldm_msgbuf_extract_uint32(ctx, dst) \
443 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930444 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300445LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300446LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930447// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930448pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030449{
450 uint32_t ldst;
451
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300452 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930453 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030454 }
455
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930456 static_assert(
457 // NOLINTNEXTLINE(bugprone-sizeof-expression)
458 sizeof(ldst) < INTMAX_MAX,
459 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930460
461 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
462 memcpy(&ldst, ctx->cursor, sizeof(ldst));
463 ldst = le32toh(ldst);
464 memcpy(dst, &ldst, sizeof(ldst));
465 ctx->cursor += sizeof(ldst);
466 ctx->remaining -= sizeof(ldst);
467 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030468 }
469
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930470 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
471 ctx->remaining -= sizeof(ldst);
472 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030473
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930474 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030475}
476
Andrew Jeffery66c77232024-04-24 11:42:02 +0930477#define pldm_msgbuf_extract_int32(ctx, dst) \
478 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930479 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300480LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300481LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930482// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930483pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030484{
485 int32_t ldst;
486
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300487 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930488 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030489 }
490
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930491 static_assert(
492 // NOLINTNEXTLINE(bugprone-sizeof-expression)
493 sizeof(ldst) < INTMAX_MAX,
494 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930495
496 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
497 memcpy(&ldst, ctx->cursor, sizeof(ldst));
498 ldst = le32toh(ldst);
499 memcpy(dst, &ldst, sizeof(ldst));
500 ctx->cursor += sizeof(ldst);
501 ctx->remaining -= sizeof(ldst);
502 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030503 }
504
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930505 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
506 ctx->remaining -= sizeof(ldst);
507 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030508
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930509 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030510}
511
Andrew Jeffery66c77232024-04-24 11:42:02 +0930512#define pldm_msgbuf_extract_real32(ctx, dst) \
513 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930514 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300515LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300516LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930517// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930518pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030519{
520 uint32_t ldst;
521
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930522 static_assert(sizeof(real32_t) == sizeof(ldst),
523 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930524
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300525 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930526 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030527 }
528
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930529 static_assert(
530 // NOLINTNEXTLINE(bugprone-sizeof-expression)
531 sizeof(ldst) < INTMAX_MAX,
532 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930533
534 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
535 memcpy(&ldst, ctx->cursor, sizeof(ldst));
536 ldst = le32toh(ldst);
537 memcpy(dst, &ldst, sizeof(ldst));
538 ctx->cursor += sizeof(ldst);
539 ctx->remaining -= sizeof(ldst);
540 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030541 }
542
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930543 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
544 ctx->remaining -= sizeof(ldst);
545 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030546
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930547 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030548}
549
Andrew Jeffery66c77232024-04-24 11:42:02 +0930550/**
551 * Extract the field at the msgbuf cursor into the lvalue named by dst.
552 *
553 * @param ctx The msgbuf context object
554 * @param dst The lvalue into which the field at the msgbuf cursor should be
555 * extracted
556 *
557 * @return PLDM_SUCCESS on success, otherwise another value on error
558 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030559#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930560 _Generic((dst), \
561 uint8_t: pldm__msgbuf_extract_uint8, \
562 int8_t: pldm__msgbuf_extract_int8, \
563 uint16_t: pldm__msgbuf_extract_uint16, \
564 int16_t: pldm__msgbuf_extract_int16, \
565 uint32_t: pldm__msgbuf_extract_uint32, \
566 int32_t: pldm__msgbuf_extract_int32, \
567 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
568
569/**
570 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
571 *
572 * @param ctx The msgbuf context object
573 * @param dst The pointer to the object into which the field at the msgbuf
574 * cursor should be extracted
575 *
576 * @return PLDM_SUCCESS on success, otherwise another value on error
577 */
578#define pldm_msgbuf_extract_p(ctx, dst) \
579 _Generic((dst), \
580 uint8_t *: pldm__msgbuf_extract_uint8, \
581 int8_t *: pldm__msgbuf_extract_int8, \
582 uint16_t *: pldm__msgbuf_extract_uint16, \
583 int16_t *: pldm__msgbuf_extract_int16, \
584 uint32_t *: pldm__msgbuf_extract_uint32, \
585 int32_t *: pldm__msgbuf_extract_int32, \
586 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030587
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000588/**
589 * @ref pldm_msgbuf_extract_array
590 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300591LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000592LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300593LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930594// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000595pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
596 void *dst, size_t dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930597{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300598 if (!ctx->cursor || count > dst_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930599 return -EINVAL;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930600 }
601
602 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930603 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930604 }
605
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930606#if INTMAX_MAX < SIZE_MAX
607 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930608 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930609 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930610#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930611
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930612 if (ctx->remaining >= (intmax_t)count) {
613 memcpy(dst, ctx->cursor, count);
614 ctx->cursor += count;
615 ctx->remaining -= (intmax_t)count;
616 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930617 }
618
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930619 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
620 ctx->remaining -= (intmax_t)count;
621 }
Andrew Jeffery369b1212023-04-20 15:44:48 +0930622
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930623 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930624}
625
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000626/**
627 * @ref pldm_msgbuf_extract_array
628 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300629LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000630LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300631LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000632pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
633 size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930634{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000635 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930636}
637
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000638/**
639 * @ref pldm_msgbuf_extract_array
640 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300641LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000642LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300643LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000644pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
645 uint8_t *dst, size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930646{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000647 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930648}
649
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000650/**
651 * Extract an array of data from the msgbuf instance
652 *
653 * @param ctx - The msgbuf instance from which to extract an array of data
654 * @param count - The number of array elements to extract
655 * @param dst - The array object into which elements from @p ctx should be
656 extracted
657 * @param dst_count - The maximum number of elements to place into @p dst
658 *
659 * Note that both @p count and @p dst_count can only be counted by `sizeof` for
660 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
661 * of array elements and _not_ the object size of the array.
662 */
663#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930664 _Generic((*(dst)), \
665 uint8_t: pldm_msgbuf_extract_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000666 char: pldm_msgbuf_extract_array_char)(ctx, count, dst, \
667 dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930668
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300669LIBPLDM_CC_NONNULL
Matt Johnstone8d8d332024-10-28 17:13:32 +0800670LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint64(struct pldm_msgbuf *ctx,
671 const uint64_t src)
672{
673 uint64_t val = htole64(src);
674
675 if (!ctx->cursor) {
676 return -EINVAL;
677 }
678
679 static_assert(
680 // NOLINTNEXTLINE(bugprone-sizeof-expression)
681 sizeof(src) < INTMAX_MAX,
682 "The following addition may not uphold the runtime assertion");
683
684 if (ctx->remaining >= (intmax_t)sizeof(src)) {
685 memcpy(ctx->cursor, &val, sizeof(val));
686 ctx->cursor += sizeof(src);
687 ctx->remaining -= sizeof(src);
688 return 0;
689 }
690
691 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
692 ctx->remaining -= sizeof(src);
693 }
694
695 return -EOVERFLOW;
696}
697
698LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300699LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
700 const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700701{
702 uint32_t val = htole32(src);
703
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930704 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930705 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700706 }
707
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930708 static_assert(
709 // NOLINTNEXTLINE(bugprone-sizeof-expression)
710 sizeof(src) < INTMAX_MAX,
711 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930712
713 if (ctx->remaining >= (intmax_t)sizeof(src)) {
714 memcpy(ctx->cursor, &val, sizeof(val));
715 ctx->cursor += sizeof(src);
716 ctx->remaining -= sizeof(src);
717 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700718 }
719
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930720 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
721 ctx->remaining -= sizeof(src);
722 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700723
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930724 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700725}
726
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300727LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300728LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
729 const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700730{
731 uint16_t val = htole16(src);
732
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930733 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930734 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700735 }
736
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930737 static_assert(
738 // NOLINTNEXTLINE(bugprone-sizeof-expression)
739 sizeof(src) < INTMAX_MAX,
740 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930741
742 if (ctx->remaining >= (intmax_t)sizeof(src)) {
743 memcpy(ctx->cursor, &val, sizeof(val));
744 ctx->cursor += sizeof(src);
745 ctx->remaining -= sizeof(src);
746 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700747 }
748
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930749 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
750 ctx->remaining -= sizeof(src);
751 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700752
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930753 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700754}
755
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300756LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300757LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
758 const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700759{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930760 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930761 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700762 }
763
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930764 static_assert(
765 // NOLINTNEXTLINE(bugprone-sizeof-expression)
766 sizeof(src) < INTMAX_MAX,
767 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930768
769 if (ctx->remaining >= (intmax_t)sizeof(src)) {
770 memcpy(ctx->cursor, &src, sizeof(src));
771 ctx->cursor += sizeof(src);
772 ctx->remaining -= sizeof(src);
773 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700774 }
775
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930776 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
777 ctx->remaining -= sizeof(src);
778 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700779
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930780 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700781}
782
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300783LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300784LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
785 const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700786{
787 int32_t val = htole32(src);
788
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930789 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930790 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700791 }
792
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930793 static_assert(
794 // NOLINTNEXTLINE(bugprone-sizeof-expression)
795 sizeof(src) < INTMAX_MAX,
796 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930797
798 if (ctx->remaining >= (intmax_t)sizeof(src)) {
799 memcpy(ctx->cursor, &val, sizeof(val));
800 ctx->cursor += sizeof(src);
801 ctx->remaining -= sizeof(src);
802 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700803 }
804
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930805 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
806 ctx->remaining -= sizeof(src);
807 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700808
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930809 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700810}
811
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300812LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300813LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
814 const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700815{
816 int16_t val = htole16(src);
817
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930818 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930819 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700820 }
821
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930822 static_assert(
823 // NOLINTNEXTLINE(bugprone-sizeof-expression)
824 sizeof(src) < INTMAX_MAX,
825 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930826
827 if (ctx->remaining >= (intmax_t)sizeof(src)) {
828 memcpy(ctx->cursor, &val, sizeof(val));
829 ctx->cursor += sizeof(src);
830 ctx->remaining -= sizeof(src);
831 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700832 }
833
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930834 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
835 ctx->remaining -= sizeof(src);
836 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700837
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930838 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700839}
840
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300841LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300842LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
843 const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700844{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930845 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930846 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700847 }
848
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930849 static_assert(
850 // NOLINTNEXTLINE(bugprone-sizeof-expression)
851 sizeof(src) < INTMAX_MAX,
852 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930853
854 if (ctx->remaining >= (intmax_t)sizeof(src)) {
855 memcpy(ctx->cursor, &src, sizeof(src));
856 ctx->cursor += sizeof(src);
857 ctx->remaining -= sizeof(src);
858 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700859 }
860
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930861 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
862 ctx->remaining -= sizeof(src);
863 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700864
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930865 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700866}
867
868#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930869 _Generic((src), \
870 uint8_t: pldm_msgbuf_insert_uint8, \
871 int8_t: pldm_msgbuf_insert_int8, \
872 uint16_t: pldm_msgbuf_insert_uint16, \
873 int16_t: pldm_msgbuf_insert_int16, \
874 uint32_t: pldm_msgbuf_insert_uint32, \
Matt Johnstone8d8d332024-10-28 17:13:32 +0800875 int32_t: pldm_msgbuf_insert_int32, \
876 uint64_t: pldm_msgbuf_insert_uint64)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700877
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000878/**
879 * @ref pldm_msgbuf_insert_array
880 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300881LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000882LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300883LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930884// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000885pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
886 const void *src, size_t src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700887{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300888 if (!ctx->cursor || count > src_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930889 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700890 }
891
892 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930893 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700894 }
895
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930896#if INTMAX_MAX < SIZE_MAX
897 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930898 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700899 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930900#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700901
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930902 if (ctx->remaining >= (intmax_t)count) {
903 memcpy(ctx->cursor, src, count);
904 ctx->cursor += count;
905 ctx->remaining -= (intmax_t)count;
906 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700907 }
908
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930909 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
910 ctx->remaining -= (intmax_t)count;
911 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700912
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930913 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700914}
915
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000916/**
917 * @ref pldm_msgbuf_insert_array
918 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300919LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000920LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300921LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000922pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
923 const char *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930924{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000925 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930926}
927
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000928/**
929 * @ref pldm_msgbuf_insert_array
930 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300931LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000932LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300933LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000934pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
935 const uint8_t *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930936{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000937 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930938}
939
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000940/**
941 * Insert an array of data into the msgbuf instance
942 *
943 * @param ctx - The msgbuf instance into which the array of data should be
944 * inserted
945 * @param count - The number of array elements to insert
946 * @param src - The array object from which elements should be inserted into
947 @p ctx
948 * @param src_count - The maximum number of elements to insert from @p src
949 *
950 * Note that both @p count and @p src_count can only be counted by `sizeof` for
951 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
952 * of array elements and _not_ the object size of the array.
953 */
954#define pldm_msgbuf_insert_array(dst, count, src, src_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930955 _Generic((*(src)), \
956 uint8_t: pldm_msgbuf_insert_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000957 char: pldm_msgbuf_insert_array_char)(dst, count, src, \
958 src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700959
Varsha Kaverappa79393822024-08-07 00:40:13 -0500960LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300961LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
962 size_t required,
963 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700964{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +1030965 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930966 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700967 }
968
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930969#if INTMAX_MAX < SIZE_MAX
970 if (required > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930971 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700972 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930973#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700974
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930975 if (ctx->remaining >= (intmax_t)required) {
976 if (cursor) {
977 *cursor = ctx->cursor;
978 }
979 ctx->cursor += required;
980 ctx->remaining -= (intmax_t)required;
981 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700982 }
983
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930984 if (ctx->remaining >= INTMAX_MIN + (intmax_t)required) {
985 ctx->remaining -= (intmax_t)required;
Varsha Kaverappa79393822024-08-07 00:40:13 -0500986 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700987
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930988 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700989}
990
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300991LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300992LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen9c83d682024-07-02 08:43:09 +0000993pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
994 size_t *length)
995{
996 intmax_t measured;
997
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +1030998 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930999 return -EINVAL;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001000 }
1001
1002 if (ctx->remaining < 0) {
1003 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301004 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001005 }
1006
1007 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1008 if (measured == ctx->remaining) {
1009 /*
1010 * We have hit the end of the buffer prior to the NUL terminator.
1011 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301012 * ctx->remaining negative ensures the `pldm_msgbuf_complete*()` APIs also
Thu Nguyen9c83d682024-07-02 08:43:09 +00001013 * return an error.
1014 */
1015 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301016 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001017 }
1018
1019 /* Include the NUL terminator in the span length, as spans are opaque */
1020 measured++;
1021
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301022 if (ctx->remaining >= measured) {
1023 if (cursor) {
1024 *cursor = ctx->cursor;
1025 }
1026
1027 ctx->cursor += measured;
1028
1029 if (length) {
1030 *length = measured;
1031 }
1032
1033 ctx->remaining -= measured;
1034 return 0;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001035 }
1036
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301037 if (ctx->remaining >= INTMAX_MIN + measured) {
1038 ctx->remaining -= measured;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001039 }
1040
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301041 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001042}
1043
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001044LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001045LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen15237782024-07-02 09:30:41 +00001046pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1047 size_t *length)
1048{
1049 static const char16_t term = 0;
1050 ptrdiff_t measured;
1051 void *end;
1052
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301053 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301054 return -EINVAL;
Thu Nguyen15237782024-07-02 09:30:41 +00001055 }
1056
1057 if (ctx->remaining < 0) {
1058 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301059 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001060 }
1061
1062 /*
1063 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1064 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1065 * start of the string
1066 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301067 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001068 do {
1069 if (end != ctx->cursor) {
1070 /*
1071 * If we've looped we've found a relatively-unaligned NUL code-point.
1072 * Scan again from a relatively-aligned start point.
1073 */
1074 end = (char *)end + 1;
1075 }
1076 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301077 end = memmem(end, ctx->remaining - measured, &term,
1078 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001079 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1080
1081 if (!end) {
1082 /*
1083 * Optimistically, the last required pattern byte was one beyond the end of
1084 * the buffer. Setting ctx->remaining negative ensures the
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301085 * `pldm_msgbuf_complete*()` APIs also return an error.
Thu Nguyen15237782024-07-02 09:30:41 +00001086 */
1087 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301088 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001089 }
1090
1091 end = (char *)end + sizeof(char16_t);
1092 measured = (char *)end - (char *)ctx->cursor;
1093
1094#if INTMAX_MAX < PTRDIFF_MAX
1095 if (measured >= INTMAX_MAX) {
1096 return pldm_msgbuf_status(ctx, EOVERFLOW);
1097 }
1098#endif
1099
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301100 if (ctx->remaining >= (intmax_t)measured) {
1101 if (cursor) {
1102 *cursor = ctx->cursor;
1103 }
1104
1105 ctx->cursor += measured;
1106
1107 if (length) {
1108 *length = (size_t)measured;
1109 }
1110
1111 ctx->remaining -= (intmax_t)measured;
1112 return 0;
Thu Nguyen15237782024-07-02 09:30:41 +00001113 }
1114
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301115 if (ctx->remaining >= INTMAX_MIN + (intmax_t)measured) {
1116 ctx->remaining -= (intmax_t)measured;
Thu Nguyen15237782024-07-02 09:30:41 +00001117 }
1118
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301119 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001120}
1121
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001122LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001123LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301124pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001125{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301126 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301127 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +07001128 }
1129
Thu Nguyen062c8762023-04-22 20:45:04 +07001130 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301131 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +07001132 }
1133
1134 *cursor = ctx->cursor;
1135 ctx->cursor += ctx->remaining;
1136 *len = ctx->remaining;
1137 ctx->remaining = 0;
1138
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301139 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001140}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001141
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001142LIBPLDM_CC_NONNULL
1143LIBPLDM_CC_ALWAYS_INLINE int
1144pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
1145{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301146 if (!ctx->cursor) {
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001147 return -EINVAL;
1148 }
1149
1150 if (ctx->remaining < 0) {
1151 return -EOVERFLOW;
1152 }
1153
1154 *cursor = ctx->cursor;
1155 *len = ctx->remaining;
1156
1157 return 0;
1158}
1159
1160LIBPLDM_CC_NONNULL
1161LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf *ctx,
1162 size_t count)
1163{
1164 if (!ctx->cursor) {
1165 return -EINVAL;
1166 }
1167
1168#if INTMAX_MAX < SIZE_MAX
1169 if (count > INTMAX_MAX) {
1170 return -EOVERFLOW;
1171 }
1172#endif
1173
Andrew Jeffery7e68f342025-03-03 21:37:23 +10301174 if (ctx->remaining >= (intmax_t)count) {
1175 ctx->cursor += count;
1176 ctx->remaining -= (intmax_t)count;
1177 return 0;
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001178 }
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001179
Andrew Jeffery7e68f342025-03-03 21:37:23 +10301180 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
1181 ctx->remaining -= (intmax_t)count;
1182 }
1183
1184 return -EOVERFLOW;
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001185}
1186
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001187/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301188 * @brief Complete the pldm_msgbuf instance and return the number of bytes
1189 * consumed.
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001190 *
1191 * @param ctx - The msgbuf.
1192 * @param orig_len - The original size of the msgbuf, the `len` argument passed to
1193 * pldm_msgbuf_init_errno().
1194 * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
1195 *
1196 * This can be called after a number of pldm_msgbuf_insert...() calls to
1197 * determine the total size that was written.
1198 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301199 * @return 0 on success, -EOVERFLOW if an implausible orig_len was provided or
1200 * an out-of-bounds access occurred.
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001201 */
1202LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +10301203LIBPLDM_CC_ALWAYS_INLINE
1204LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301205int pldm_msgbuf_complete_used(struct pldm_msgbuf *ctx, size_t orig_len,
1206 size_t *ret_used_len)
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001207{
1208 int rc;
Andrew Jeffery704e4d52025-03-03 17:13:50 +10301209
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001210 rc = pldm_msgbuf_validate(ctx);
1211 if (rc) {
1212 return rc;
1213 }
1214
1215 if ((size_t)ctx->remaining > orig_len) {
1216 /* Caller passed incorrect orig_len */
1217 return -EOVERFLOW;
1218 }
1219
1220 *ret_used_len = orig_len - ctx->remaining;
1221 return 0;
1222}
1223
1224/**
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001225 * @brief pldm_msgbuf copy data between two msg buffers
1226 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301227 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1228 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001229 * @param[in] size - size of data to be copied
1230 * @param[in] description - description of data copied
1231 *
1232 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1233 * PLDM_ERROR_INVALID_LENGTH otherwise.
1234 * PLDM_ERROR_INVALID_DATA if input is invalid
1235 */
1236#define pldm_msgbuf_copy(dst, src, type, name) \
1237 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001238LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001239LIBPLDM_CC_ALWAYS_INLINE int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001240// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301241pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001242 const char *description LIBPLDM_CC_UNUSED)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001243{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001244 if (!src->cursor || !dst->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301245 return -EINVAL;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001246 }
1247
1248#if INTMAX_MAX < SIZE_MAX
1249 if (size > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301250 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001251 }
1252#endif
1253
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301254 if (src->remaining >= (intmax_t)size &&
1255 dst->remaining >= (intmax_t)size) {
1256 memcpy(dst->cursor, src->cursor, size);
1257 src->cursor += size;
1258 src->remaining -= (intmax_t)size;
1259 dst->cursor += size;
1260 dst->remaining -= (intmax_t)size;
1261 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001262 }
1263
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301264 if (src->remaining >= INTMAX_MIN + (intmax_t)size) {
1265 src->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001266 }
1267
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301268 if (dst->remaining >= INTMAX_MIN + (intmax_t)size) {
1269 dst->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001270 }
1271
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301272 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001273}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301274
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001275LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001276LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001277LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery8b879602024-07-08 12:50:19 +09301278pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1279{
1280 void *ascii = NULL;
1281 size_t len = 0;
1282 int rc;
1283
1284 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1285 if (rc < 0) {
1286 return rc;
1287 }
1288
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001289 return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
Andrew Jeffery8b879602024-07-08 12:50:19 +09301290}
1291
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001292LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001293LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001294LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301295pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1296{
1297 void *utf16 = NULL;
1298 size_t len = 0;
1299 int rc;
1300
1301 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1302 if (rc < 0) {
1303 return rc;
1304 }
1305
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001306 return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301307}
1308
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301309#ifdef __cplusplus
1310}
1311#endif
1312
Andrew Jeffery66c77232024-04-24 11:42:02 +09301313#ifdef __cplusplus
1314#include <type_traits>
1315
1316template <typename T>
1317static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1318 void *buf)
1319{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301320 static_assert(std::is_same<uint8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301321 return pldm__msgbuf_extract_uint8(ctx, buf);
1322}
1323
1324template <typename T>
1325static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1326 void *buf)
1327{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301328 static_assert(std::is_same<int8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301329 return pldm__msgbuf_extract_int8(ctx, buf);
1330}
1331
1332template <typename T>
1333static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1334 void *buf)
1335{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301336 static_assert(std::is_same<uint16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301337 return pldm__msgbuf_extract_uint16(ctx, buf);
1338}
1339
1340template <typename T>
1341static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1342 void *buf)
1343{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301344 static_assert(std::is_same<int16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301345 return pldm__msgbuf_extract_int16(ctx, buf);
1346}
1347
1348template <typename T>
1349static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1350 void *buf)
1351{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301352 static_assert(std::is_same<uint32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301353 return pldm__msgbuf_extract_uint32(ctx, buf);
1354}
1355
1356template <typename T>
1357static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1358 void *buf)
1359{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301360 static_assert(std::is_same<int32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301361 return pldm__msgbuf_extract_int32(ctx, buf);
1362}
1363
1364template <typename T>
1365static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1366 void *buf)
1367{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301368 static_assert(std::is_same<real32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301369 return pldm__msgbuf_extract_real32(ctx, buf);
1370}
1371#endif
1372
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301373#endif /* BUF_H */