blob: 437b4230f9b95d1fe0e15cf0bc354e2ad90af8ce [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
147 * and no overflow has occurred. Otherwise, -EBADMSG.
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930148 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300149LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030150LIBPLDM_CC_ALWAYS_INLINE
151LIBPLDM_CC_WARN_UNUSED_RESULT
152int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930153{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930154 if (ctx->remaining != 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930155 return -EBADMSG;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930156 }
157
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930158 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930159}
160
161/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030162 * @brief Complete the pldm_msgbuf instance
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030163 *
164 * @param[in] ctx - pldm_msgbuf context for extractor
165 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030166 * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030167 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300168LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030169LIBPLDM_CC_ALWAYS_INLINE
170LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030171int pldm_msgbuf_complete(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030172{
173 int valid;
174
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030175 valid = pldm_msgbuf_validate(ctx);
176
177 ctx->cursor = NULL;
178 ctx->remaining = 0;
179
180 return valid;
181}
182
183/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030184 * @brief Complete the pldm_msgbuf instance, and check that the underlying buffer
185 * has been entirely consumed without overflow
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930186 *
187 * @param[in] ctx - pldm_msgbuf context
188 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030189 * @return 0 if all buffer access were in-bounds and completely consume the
190 * underlying buffer. Otherwise, -EBADMSG.
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930191 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300192LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +1030193LIBPLDM_CC_ALWAYS_INLINE
194LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030195int pldm_msgbuf_complete_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930196{
197 int consumed;
198
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930199 consumed = pldm_msgbuf_consumed(ctx);
200
201 ctx->cursor = NULL;
202 ctx->remaining = 0;
203
204 return consumed;
205}
206
Andrew Jeffery66c77232024-04-24 11:42:02 +0930207/*
208 * Exploit the pre-processor to perform type checking by macro substitution.
209 *
210 * A C type is defined by its alignment as well as its object
211 * size, and compilers have a hammer to enforce it in the form of
212 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
213 * the libpldm public API this presents a problem: Naively attempting to use the
214 * msgbuf APIs on a member of a packed struct would yield an error.
215 *
216 * The msgbuf APIs are implemented such that data is moved through unaligned
217 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
218 * make the object pointers take a trip through `void *` at its API boundary.
219 * That presents a bit too much of an opportunity to non-surgically remove your
220 * own foot, so here we set about doing something to mitigate that as well.
221 *
222 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
223 * only for the purpose of object sizes, disregarding alignment. We have a few
224 * constraints that cause some headaches:
225 *
226 * 1. We have to perform the type-check before a call through a C function,
227 * as the function must take the object pointer argument as `void *`.
228 * Essentially, this constrains us to doing something with macros.
229 *
230 * 2. While libpldm is a C library, its test suite is written in C++ to take
231 * advantage of gtest.
232 *
233 * 3. Ideally we'd do something with C's `static_assert()`, however
234 * `static_assert()` is defined as void, and as we're constrained to macros,
235 * using `static_assert()` would require a statement-expression
236 *
237 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
238 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
239 * the purpose of enabling statement-expressions in this one instance.
240 *
241 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
242 * however it's implemented in terms of `_Generic()`, which is not available
243 * in C++.
244 *
245 * Combined this means we need separate solutions for C and C++.
246 *
247 * For C, as we don't have statement-expressions, we need to exploit some other
248 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
249 * API function call. We also have to take care of the fact that the call-sites
250 * may be in the context of a variable assignment for error-handling purposes.
251 * The key observation is that we can use the comma operator as a sequence point
252 * to order the type check before the API call, discarding the "result" value of
253 * the type check and yielding the return value of the API call.
254 *
255 * C++ could be less of a headache than the C as we can leverage template
256 * functions. An advantage of template functions is that while their definition
257 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530258 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930259 * we have in the C path. However, the use of the msgbuf APIs in the test suite
260 * still makes things somewhat tricky, as the call-sites in the test suite are
261 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
262 * takes both the object type and the required type as template arguments, and
263 * then define the object pointer parameter as `void *` for a call through to
264 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
265 * encapsulated in gtest macros, use of commas in the template specification
266 * causes pre-processor confusion. In this way we're constrained to only one
267 * template argument per function.
268 *
269 * Implement the C++ path using template functions that take the destination
270 * object type as a template argument, while the name of the function symbols
271 * are derived from the required type. The manual implementations of these
272 * appear at the end of the header. The type safety is actually enforced
273 * by `static_assert()` this time, as we can use statements as we're not
274 * constrained to an expression in the templated function body.
275 *
276 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
277 * double-evaluation of some arguments. We're not yet bothered by this for two
278 * reasons:
279 *
280 * 1. The nature of the current call-sites are such that there are no
281 * argument expressions that result in undesirable side-effects
282 *
283 * 2. It's an API internal to the libpldm implementation, and we can fix things
284 * whenever something crops up the violates the observation in 1.
285 */
286#ifdef __cplusplus
287#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
288 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
289#else
290#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
291 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
292#endif
293
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930294/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030295 * @brief pldm_msgbuf extractor for a uint8_t
296 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530297 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030298 * @param[out] dst - destination of extracted value
299 *
300 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
301 * PLDM_ERROR_INVALID_LENGTH otherwise.
302 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
303 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930304#define pldm_msgbuf_extract_uint8(ctx, dst) \
305 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930306 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300307LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300308LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930309// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930310pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030311{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300312 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930313 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030314 }
315
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930316 if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
317 memcpy(dst, ctx->cursor, sizeof(uint8_t));
318 ctx->cursor++;
319 ctx->remaining -= sizeof(uint8_t);
320 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030321 }
322
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930323 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
324 ctx->remaining -= sizeof(uint8_t);
325 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930326
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930327 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030328}
329
Andrew Jeffery66c77232024-04-24 11:42:02 +0930330#define pldm_msgbuf_extract_int8(ctx, dst) \
331 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930332 ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300333LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300334LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930335// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930336pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030337{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300338 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930339 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030340 }
341
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930342 if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
343 memcpy(dst, ctx->cursor, sizeof(int8_t));
344 ctx->cursor++;
345 ctx->remaining -= sizeof(int8_t);
346 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030347 }
348
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930349 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
350 ctx->remaining -= sizeof(int8_t);
351 }
352
353 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030354}
355
Andrew Jeffery66c77232024-04-24 11:42:02 +0930356#define pldm_msgbuf_extract_uint16(ctx, dst) \
357 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930358 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300359LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300360LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930361// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930362pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030363{
364 uint16_t ldst;
365
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300366 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930367 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030368 }
369
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930370 // Check for underflow while tracking the magnitude of the buffer overflow
371 static_assert(
372 // NOLINTNEXTLINE(bugprone-sizeof-expression)
373 sizeof(ldst) < INTMAX_MAX,
374 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930375
376 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
377 // Use memcpy() to have the compiler deal with any alignment
378 // issues on the target architecture
379 memcpy(&ldst, ctx->cursor, sizeof(ldst));
380
381 // Only assign the target value once it's correctly decoded
382 ldst = le16toh(ldst);
383
384 // Allow storing to unaligned
385 memcpy(dst, &ldst, sizeof(ldst));
386
387 ctx->cursor += sizeof(ldst);
388 ctx->remaining -= sizeof(ldst);
389 return 0;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930390 }
391
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930392 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
393 ctx->remaining -= sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030394 }
395
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930396 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030397}
398
Andrew Jeffery66c77232024-04-24 11:42:02 +0930399#define pldm_msgbuf_extract_int16(ctx, dst) \
400 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930401 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300402LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300403LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930404// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930405pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030406{
407 int16_t ldst;
408
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300409 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930410 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030411 }
412
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930413 static_assert(
414 // NOLINTNEXTLINE(bugprone-sizeof-expression)
415 sizeof(ldst) < INTMAX_MAX,
416 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930417
418 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
419 memcpy(&ldst, ctx->cursor, sizeof(ldst));
420 ldst = le16toh(ldst);
421 memcpy(dst, &ldst, sizeof(ldst));
422 ctx->cursor += sizeof(ldst);
423 ctx->remaining -= sizeof(ldst);
424 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030425 }
426
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930427 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
428 ctx->remaining -= sizeof(ldst);
429 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030430
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930431 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030432}
433
Andrew Jeffery66c77232024-04-24 11:42:02 +0930434#define pldm_msgbuf_extract_uint32(ctx, dst) \
435 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930436 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300437LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300438LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930439// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930440pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030441{
442 uint32_t ldst;
443
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300444 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930445 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030446 }
447
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930448 static_assert(
449 // NOLINTNEXTLINE(bugprone-sizeof-expression)
450 sizeof(ldst) < INTMAX_MAX,
451 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930452
453 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
454 memcpy(&ldst, ctx->cursor, sizeof(ldst));
455 ldst = le32toh(ldst);
456 memcpy(dst, &ldst, sizeof(ldst));
457 ctx->cursor += sizeof(ldst);
458 ctx->remaining -= sizeof(ldst);
459 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030460 }
461
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930462 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
463 ctx->remaining -= sizeof(ldst);
464 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030465
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930466 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030467}
468
Andrew Jeffery66c77232024-04-24 11:42:02 +0930469#define pldm_msgbuf_extract_int32(ctx, dst) \
470 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930471 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300472LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300473LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930474// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930475pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030476{
477 int32_t ldst;
478
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300479 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930480 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030481 }
482
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930483 static_assert(
484 // NOLINTNEXTLINE(bugprone-sizeof-expression)
485 sizeof(ldst) < INTMAX_MAX,
486 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930487
488 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
489 memcpy(&ldst, ctx->cursor, sizeof(ldst));
490 ldst = le32toh(ldst);
491 memcpy(dst, &ldst, sizeof(ldst));
492 ctx->cursor += sizeof(ldst);
493 ctx->remaining -= sizeof(ldst);
494 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030495 }
496
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930497 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
498 ctx->remaining -= sizeof(ldst);
499 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030500
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930501 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030502}
503
Andrew Jeffery66c77232024-04-24 11:42:02 +0930504#define pldm_msgbuf_extract_real32(ctx, dst) \
505 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930506 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300507LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300508LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930509// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930510pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030511{
512 uint32_t ldst;
513
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930514 static_assert(sizeof(real32_t) == sizeof(ldst),
515 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930516
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300517 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930518 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030519 }
520
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930521 static_assert(
522 // NOLINTNEXTLINE(bugprone-sizeof-expression)
523 sizeof(ldst) < INTMAX_MAX,
524 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930525
526 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
527 memcpy(&ldst, ctx->cursor, sizeof(ldst));
528 ldst = le32toh(ldst);
529 memcpy(dst, &ldst, sizeof(ldst));
530 ctx->cursor += sizeof(ldst);
531 ctx->remaining -= sizeof(ldst);
532 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030533 }
534
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930535 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
536 ctx->remaining -= sizeof(ldst);
537 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030538
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930539 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030540}
541
Andrew Jeffery66c77232024-04-24 11:42:02 +0930542/**
543 * Extract the field at the msgbuf cursor into the lvalue named by dst.
544 *
545 * @param ctx The msgbuf context object
546 * @param dst The lvalue into which the field at the msgbuf cursor should be
547 * extracted
548 *
549 * @return PLDM_SUCCESS on success, otherwise another value on error
550 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030551#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930552 _Generic((dst), \
553 uint8_t: pldm__msgbuf_extract_uint8, \
554 int8_t: pldm__msgbuf_extract_int8, \
555 uint16_t: pldm__msgbuf_extract_uint16, \
556 int16_t: pldm__msgbuf_extract_int16, \
557 uint32_t: pldm__msgbuf_extract_uint32, \
558 int32_t: pldm__msgbuf_extract_int32, \
559 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
560
561/**
562 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
563 *
564 * @param ctx The msgbuf context object
565 * @param dst The pointer to the object into which the field at the msgbuf
566 * cursor should be extracted
567 *
568 * @return PLDM_SUCCESS on success, otherwise another value on error
569 */
570#define pldm_msgbuf_extract_p(ctx, dst) \
571 _Generic((dst), \
572 uint8_t *: pldm__msgbuf_extract_uint8, \
573 int8_t *: pldm__msgbuf_extract_int8, \
574 uint16_t *: pldm__msgbuf_extract_uint16, \
575 int16_t *: pldm__msgbuf_extract_int16, \
576 uint32_t *: pldm__msgbuf_extract_uint32, \
577 int32_t *: pldm__msgbuf_extract_int32, \
578 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030579
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000580/**
581 * @ref pldm_msgbuf_extract_array
582 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300583LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000584LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300585LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930586// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000587pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
588 void *dst, size_t dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930589{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300590 if (!ctx->cursor || count > dst_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930591 return -EINVAL;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930592 }
593
594 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930595 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930596 }
597
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930598#if INTMAX_MAX < SIZE_MAX
599 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930600 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930601 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930602#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930603
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930604 if (ctx->remaining >= (intmax_t)count) {
605 memcpy(dst, ctx->cursor, count);
606 ctx->cursor += count;
607 ctx->remaining -= (intmax_t)count;
608 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930609 }
610
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930611 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
612 ctx->remaining -= (intmax_t)count;
613 }
Andrew Jeffery369b1212023-04-20 15:44:48 +0930614
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930615 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930616}
617
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000618/**
619 * @ref pldm_msgbuf_extract_array
620 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300621LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000622LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300623LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000624pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
625 size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930626{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000627 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930628}
629
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000630/**
631 * @ref pldm_msgbuf_extract_array
632 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300633LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000634LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300635LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000636pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
637 uint8_t *dst, size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930638{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000639 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930640}
641
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000642/**
643 * Extract an array of data from the msgbuf instance
644 *
645 * @param ctx - The msgbuf instance from which to extract an array of data
646 * @param count - The number of array elements to extract
647 * @param dst - The array object into which elements from @p ctx should be
648 extracted
649 * @param dst_count - The maximum number of elements to place into @p dst
650 *
651 * Note that both @p count and @p dst_count can only be counted by `sizeof` for
652 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
653 * of array elements and _not_ the object size of the array.
654 */
655#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930656 _Generic((*(dst)), \
657 uint8_t: pldm_msgbuf_extract_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000658 char: pldm_msgbuf_extract_array_char)(ctx, count, dst, \
659 dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930660
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300661LIBPLDM_CC_NONNULL
Matt Johnstone8d8d332024-10-28 17:13:32 +0800662LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint64(struct pldm_msgbuf *ctx,
663 const uint64_t src)
664{
665 uint64_t val = htole64(src);
666
667 if (!ctx->cursor) {
668 return -EINVAL;
669 }
670
671 static_assert(
672 // NOLINTNEXTLINE(bugprone-sizeof-expression)
673 sizeof(src) < INTMAX_MAX,
674 "The following addition may not uphold the runtime assertion");
675
676 if (ctx->remaining >= (intmax_t)sizeof(src)) {
677 memcpy(ctx->cursor, &val, sizeof(val));
678 ctx->cursor += sizeof(src);
679 ctx->remaining -= sizeof(src);
680 return 0;
681 }
682
683 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
684 ctx->remaining -= sizeof(src);
685 }
686
687 return -EOVERFLOW;
688}
689
690LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300691LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
692 const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700693{
694 uint32_t val = htole32(src);
695
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930696 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930697 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700698 }
699
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930700 static_assert(
701 // NOLINTNEXTLINE(bugprone-sizeof-expression)
702 sizeof(src) < INTMAX_MAX,
703 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930704
705 if (ctx->remaining >= (intmax_t)sizeof(src)) {
706 memcpy(ctx->cursor, &val, sizeof(val));
707 ctx->cursor += sizeof(src);
708 ctx->remaining -= sizeof(src);
709 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700710 }
711
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930712 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
713 ctx->remaining -= sizeof(src);
714 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700715
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930716 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700717}
718
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300719LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300720LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
721 const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700722{
723 uint16_t val = htole16(src);
724
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930725 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930726 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700727 }
728
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930729 static_assert(
730 // NOLINTNEXTLINE(bugprone-sizeof-expression)
731 sizeof(src) < INTMAX_MAX,
732 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930733
734 if (ctx->remaining >= (intmax_t)sizeof(src)) {
735 memcpy(ctx->cursor, &val, sizeof(val));
736 ctx->cursor += sizeof(src);
737 ctx->remaining -= sizeof(src);
738 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700739 }
740
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930741 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
742 ctx->remaining -= sizeof(src);
743 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700744
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930745 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700746}
747
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300748LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300749LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
750 const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700751{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930752 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930753 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700754 }
755
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930756 static_assert(
757 // NOLINTNEXTLINE(bugprone-sizeof-expression)
758 sizeof(src) < INTMAX_MAX,
759 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930760
761 if (ctx->remaining >= (intmax_t)sizeof(src)) {
762 memcpy(ctx->cursor, &src, sizeof(src));
763 ctx->cursor += sizeof(src);
764 ctx->remaining -= sizeof(src);
765 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700766 }
767
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930768 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
769 ctx->remaining -= sizeof(src);
770 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700771
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930772 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700773}
774
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300775LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300776LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
777 const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700778{
779 int32_t val = htole32(src);
780
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930781 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930782 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700783 }
784
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930785 static_assert(
786 // NOLINTNEXTLINE(bugprone-sizeof-expression)
787 sizeof(src) < INTMAX_MAX,
788 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930789
790 if (ctx->remaining >= (intmax_t)sizeof(src)) {
791 memcpy(ctx->cursor, &val, sizeof(val));
792 ctx->cursor += sizeof(src);
793 ctx->remaining -= sizeof(src);
794 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700795 }
796
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930797 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
798 ctx->remaining -= sizeof(src);
799 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700800
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930801 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700802}
803
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300804LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300805LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
806 const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700807{
808 int16_t val = htole16(src);
809
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930810 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930811 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700812 }
813
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930814 static_assert(
815 // NOLINTNEXTLINE(bugprone-sizeof-expression)
816 sizeof(src) < INTMAX_MAX,
817 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930818
819 if (ctx->remaining >= (intmax_t)sizeof(src)) {
820 memcpy(ctx->cursor, &val, sizeof(val));
821 ctx->cursor += sizeof(src);
822 ctx->remaining -= sizeof(src);
823 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700824 }
825
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930826 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
827 ctx->remaining -= sizeof(src);
828 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700829
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930830 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700831}
832
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300833LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300834LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
835 const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700836{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930837 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930838 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700839 }
840
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930841 static_assert(
842 // NOLINTNEXTLINE(bugprone-sizeof-expression)
843 sizeof(src) < INTMAX_MAX,
844 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930845
846 if (ctx->remaining >= (intmax_t)sizeof(src)) {
847 memcpy(ctx->cursor, &src, sizeof(src));
848 ctx->cursor += sizeof(src);
849 ctx->remaining -= sizeof(src);
850 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700851 }
852
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930853 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
854 ctx->remaining -= sizeof(src);
855 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700856
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930857 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700858}
859
860#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930861 _Generic((src), \
862 uint8_t: pldm_msgbuf_insert_uint8, \
863 int8_t: pldm_msgbuf_insert_int8, \
864 uint16_t: pldm_msgbuf_insert_uint16, \
865 int16_t: pldm_msgbuf_insert_int16, \
866 uint32_t: pldm_msgbuf_insert_uint32, \
Matt Johnstone8d8d332024-10-28 17:13:32 +0800867 int32_t: pldm_msgbuf_insert_int32, \
868 uint64_t: pldm_msgbuf_insert_uint64)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700869
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000870/**
871 * @ref pldm_msgbuf_insert_array
872 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300873LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000874LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300875LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930876// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000877pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
878 const void *src, size_t src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700879{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300880 if (!ctx->cursor || count > src_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930881 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700882 }
883
884 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930885 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700886 }
887
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930888#if INTMAX_MAX < SIZE_MAX
889 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930890 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700891 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930892#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700893
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930894 if (ctx->remaining >= (intmax_t)count) {
895 memcpy(ctx->cursor, src, count);
896 ctx->cursor += count;
897 ctx->remaining -= (intmax_t)count;
898 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700899 }
900
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930901 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
902 ctx->remaining -= (intmax_t)count;
903 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700904
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930905 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700906}
907
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000908/**
909 * @ref pldm_msgbuf_insert_array
910 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300911LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000912LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300913LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000914pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
915 const char *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930916{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000917 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930918}
919
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000920/**
921 * @ref pldm_msgbuf_insert_array
922 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300923LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000924LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300925LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000926pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
927 const uint8_t *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930928{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000929 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930930}
931
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000932/**
933 * Insert an array of data into the msgbuf instance
934 *
935 * @param ctx - The msgbuf instance into which the array of data should be
936 * inserted
937 * @param count - The number of array elements to insert
938 * @param src - The array object from which elements should be inserted into
939 @p ctx
940 * @param src_count - The maximum number of elements to insert from @p src
941 *
942 * Note that both @p count and @p src_count can only be counted by `sizeof` for
943 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
944 * of array elements and _not_ the object size of the array.
945 */
946#define pldm_msgbuf_insert_array(dst, count, src, src_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930947 _Generic((*(src)), \
948 uint8_t: pldm_msgbuf_insert_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000949 char: pldm_msgbuf_insert_array_char)(dst, count, src, \
950 src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700951
Varsha Kaverappa79393822024-08-07 00:40:13 -0500952LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300953LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
954 size_t required,
955 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700956{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +1030957 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930958 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700959 }
960
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930961#if INTMAX_MAX < SIZE_MAX
962 if (required > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930963 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700964 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930965#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700966
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930967 if (ctx->remaining >= (intmax_t)required) {
968 if (cursor) {
969 *cursor = ctx->cursor;
970 }
971 ctx->cursor += required;
972 ctx->remaining -= (intmax_t)required;
973 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700974 }
975
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930976 if (ctx->remaining >= INTMAX_MIN + (intmax_t)required) {
977 ctx->remaining -= (intmax_t)required;
Varsha Kaverappa79393822024-08-07 00:40:13 -0500978 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700979
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930980 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700981}
982
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300983LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300984LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen9c83d682024-07-02 08:43:09 +0000985pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
986 size_t *length)
987{
988 intmax_t measured;
989
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +1030990 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930991 return -EINVAL;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000992 }
993
994 if (ctx->remaining < 0) {
995 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930996 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000997 }
998
999 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1000 if (measured == ctx->remaining) {
1001 /*
1002 * We have hit the end of the buffer prior to the NUL terminator.
1003 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301004 * ctx->remaining negative ensures the `pldm_msgbuf_complete*()` APIs also
Thu Nguyen9c83d682024-07-02 08:43:09 +00001005 * return an error.
1006 */
1007 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301008 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001009 }
1010
1011 /* Include the NUL terminator in the span length, as spans are opaque */
1012 measured++;
1013
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301014 if (ctx->remaining >= measured) {
1015 if (cursor) {
1016 *cursor = ctx->cursor;
1017 }
1018
1019 ctx->cursor += measured;
1020
1021 if (length) {
1022 *length = measured;
1023 }
1024
1025 ctx->remaining -= measured;
1026 return 0;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001027 }
1028
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301029 if (ctx->remaining >= INTMAX_MIN + measured) {
1030 ctx->remaining -= measured;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001031 }
1032
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301033 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001034}
1035
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001036LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001037LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen15237782024-07-02 09:30:41 +00001038pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1039 size_t *length)
1040{
1041 static const char16_t term = 0;
1042 ptrdiff_t measured;
1043 void *end;
1044
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301045 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301046 return -EINVAL;
Thu Nguyen15237782024-07-02 09:30:41 +00001047 }
1048
1049 if (ctx->remaining < 0) {
1050 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301051 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001052 }
1053
1054 /*
1055 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1056 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1057 * start of the string
1058 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301059 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001060 do {
1061 if (end != ctx->cursor) {
1062 /*
1063 * If we've looped we've found a relatively-unaligned NUL code-point.
1064 * Scan again from a relatively-aligned start point.
1065 */
1066 end = (char *)end + 1;
1067 }
1068 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301069 end = memmem(end, ctx->remaining - measured, &term,
1070 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001071 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1072
1073 if (!end) {
1074 /*
1075 * Optimistically, the last required pattern byte was one beyond the end of
1076 * the buffer. Setting ctx->remaining negative ensures the
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301077 * `pldm_msgbuf_complete*()` APIs also return an error.
Thu Nguyen15237782024-07-02 09:30:41 +00001078 */
1079 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301080 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001081 }
1082
1083 end = (char *)end + sizeof(char16_t);
1084 measured = (char *)end - (char *)ctx->cursor;
1085
1086#if INTMAX_MAX < PTRDIFF_MAX
1087 if (measured >= INTMAX_MAX) {
1088 return pldm_msgbuf_status(ctx, EOVERFLOW);
1089 }
1090#endif
1091
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301092 if (ctx->remaining >= (intmax_t)measured) {
1093 if (cursor) {
1094 *cursor = ctx->cursor;
1095 }
1096
1097 ctx->cursor += measured;
1098
1099 if (length) {
1100 *length = (size_t)measured;
1101 }
1102
1103 ctx->remaining -= (intmax_t)measured;
1104 return 0;
Thu Nguyen15237782024-07-02 09:30:41 +00001105 }
1106
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301107 if (ctx->remaining >= INTMAX_MIN + (intmax_t)measured) {
1108 ctx->remaining -= (intmax_t)measured;
Thu Nguyen15237782024-07-02 09:30:41 +00001109 }
1110
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301111 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001112}
1113
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001114LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001115LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301116pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001117{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301118 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301119 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +07001120 }
1121
Thu Nguyen062c8762023-04-22 20:45:04 +07001122 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301123 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +07001124 }
1125
1126 *cursor = ctx->cursor;
1127 ctx->cursor += ctx->remaining;
1128 *len = ctx->remaining;
1129 ctx->remaining = 0;
1130
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301131 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001132}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001133
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001134LIBPLDM_CC_NONNULL
1135LIBPLDM_CC_ALWAYS_INLINE int
1136pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
1137{
Andrew Jeffery2b42f7f2025-03-03 21:23:13 +10301138 if (!ctx->cursor) {
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001139 return -EINVAL;
1140 }
1141
1142 if (ctx->remaining < 0) {
1143 return -EOVERFLOW;
1144 }
1145
1146 *cursor = ctx->cursor;
1147 *len = ctx->remaining;
1148
1149 return 0;
1150}
1151
1152LIBPLDM_CC_NONNULL
1153LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf *ctx,
1154 size_t count)
1155{
1156 if (!ctx->cursor) {
1157 return -EINVAL;
1158 }
1159
1160#if INTMAX_MAX < SIZE_MAX
1161 if (count > INTMAX_MAX) {
1162 return -EOVERFLOW;
1163 }
1164#endif
1165
Andrew Jeffery7e68f342025-03-03 21:37:23 +10301166 if (ctx->remaining >= (intmax_t)count) {
1167 ctx->cursor += count;
1168 ctx->remaining -= (intmax_t)count;
1169 return 0;
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001170 }
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001171
Andrew Jeffery7e68f342025-03-03 21:37:23 +10301172 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
1173 ctx->remaining -= (intmax_t)count;
1174 }
1175
1176 return -EOVERFLOW;
Matt Johnston8f3b13c2024-10-16 16:08:21 +08001177}
1178
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001179/**
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301180 * @brief Complete the pldm_msgbuf instance and return the number of bytes
1181 * consumed.
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001182 *
1183 * @param ctx - The msgbuf.
1184 * @param orig_len - The original size of the msgbuf, the `len` argument passed to
1185 * pldm_msgbuf_init_errno().
1186 * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
1187 *
1188 * This can be called after a number of pldm_msgbuf_insert...() calls to
1189 * determine the total size that was written.
1190 *
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301191 * @return 0 on success, -EOVERFLOW if an implausible orig_len was provided or
1192 * an out-of-bounds access occurred.
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001193 */
1194LIBPLDM_CC_NONNULL
Andrew Jeffery704e4d52025-03-03 17:13:50 +10301195LIBPLDM_CC_ALWAYS_INLINE
1196LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301197int pldm_msgbuf_complete_used(struct pldm_msgbuf *ctx, size_t orig_len,
1198 size_t *ret_used_len)
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001199{
1200 int rc;
Andrew Jeffery704e4d52025-03-03 17:13:50 +10301201
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001202 rc = pldm_msgbuf_validate(ctx);
1203 if (rc) {
1204 return rc;
1205 }
1206
1207 if ((size_t)ctx->remaining > orig_len) {
1208 /* Caller passed incorrect orig_len */
1209 return -EOVERFLOW;
1210 }
1211
1212 *ret_used_len = orig_len - ctx->remaining;
1213 return 0;
1214}
1215
1216/**
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001217 * @brief pldm_msgbuf copy data between two msg buffers
1218 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301219 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1220 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001221 * @param[in] size - size of data to be copied
1222 * @param[in] description - description of data copied
1223 *
1224 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1225 * PLDM_ERROR_INVALID_LENGTH otherwise.
1226 * PLDM_ERROR_INVALID_DATA if input is invalid
1227 */
1228#define pldm_msgbuf_copy(dst, src, type, name) \
1229 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001230LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001231LIBPLDM_CC_ALWAYS_INLINE int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001232// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301233pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001234 const char *description LIBPLDM_CC_UNUSED)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001235{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001236 if (!src->cursor || !dst->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301237 return -EINVAL;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001238 }
1239
1240#if INTMAX_MAX < SIZE_MAX
1241 if (size > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301242 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001243 }
1244#endif
1245
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301246 if (src->remaining >= (intmax_t)size &&
1247 dst->remaining >= (intmax_t)size) {
1248 memcpy(dst->cursor, src->cursor, size);
1249 src->cursor += size;
1250 src->remaining -= (intmax_t)size;
1251 dst->cursor += size;
1252 dst->remaining -= (intmax_t)size;
1253 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001254 }
1255
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301256 if (src->remaining >= INTMAX_MIN + (intmax_t)size) {
1257 src->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001258 }
1259
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301260 if (dst->remaining >= INTMAX_MIN + (intmax_t)size) {
1261 dst->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001262 }
1263
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301264 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001265}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301266
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001267LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001268LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001269LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery8b879602024-07-08 12:50:19 +09301270pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1271{
1272 void *ascii = NULL;
1273 size_t len = 0;
1274 int rc;
1275
1276 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1277 if (rc < 0) {
1278 return rc;
1279 }
1280
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001281 return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
Andrew Jeffery8b879602024-07-08 12:50:19 +09301282}
1283
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001284LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001285LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001286LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301287pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1288{
1289 void *utf16 = NULL;
1290 size_t len = 0;
1291 int rc;
1292
1293 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1294 if (rc < 0) {
1295 return rc;
1296 }
1297
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001298 return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301299}
1300
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301301#ifdef __cplusplus
1302}
1303#endif
1304
Andrew Jeffery66c77232024-04-24 11:42:02 +09301305#ifdef __cplusplus
1306#include <type_traits>
1307
1308template <typename T>
1309static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1310 void *buf)
1311{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301312 static_assert(std::is_same<uint8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301313 return pldm__msgbuf_extract_uint8(ctx, buf);
1314}
1315
1316template <typename T>
1317static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1318 void *buf)
1319{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301320 static_assert(std::is_same<int8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301321 return pldm__msgbuf_extract_int8(ctx, buf);
1322}
1323
1324template <typename T>
1325static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1326 void *buf)
1327{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301328 static_assert(std::is_same<uint16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301329 return pldm__msgbuf_extract_uint16(ctx, buf);
1330}
1331
1332template <typename T>
1333static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1334 void *buf)
1335{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301336 static_assert(std::is_same<int16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301337 return pldm__msgbuf_extract_int16(ctx, buf);
1338}
1339
1340template <typename T>
1341static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1342 void *buf)
1343{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301344 static_assert(std::is_same<uint32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301345 return pldm__msgbuf_extract_uint32(ctx, buf);
1346}
1347
1348template <typename T>
1349static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1350 void *buf)
1351{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301352 static_assert(std::is_same<int32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301353 return pldm__msgbuf_extract_int32(ctx, buf);
1354}
1355
1356template <typename T>
1357static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1358 void *buf)
1359{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301360 static_assert(std::is_same<real32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301361 return pldm__msgbuf_extract_real32(ctx, buf);
1362}
1363#endif
1364
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301365#endif /* BUF_H */