blob: a176891e39e41605593561119d25d19402e99bfc [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 Jefferycb569bc2024-09-01 09:38:09 +030091LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093092// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093093pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
94 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103095{
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093096 if ((minsize > len)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093097 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103098 }
99
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930100#if INTMAX_MAX < SIZE_MAX
101 if (len > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930102 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930103 }
104#endif
105
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930106 if (UINTPTR_MAX - (uintptr_t)buf < len) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930107 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030108 }
109
110 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930111 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030112
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930113 return 0;
114}
115
116/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030117 * @brief Validate buffer overflow state
118 *
119 * @param[in] ctx - pldm_msgbuf context for extractor
120 *
121 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
122 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
123 * prior accesses would have occurred beyond the bounds of the buffer, and
124 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
125 * pointer.
126 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300127LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300128LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030129{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930130 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930131 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030132 }
133
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930134 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030135}
136
137/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930138 * @brief Test whether a message buffer has been exactly consumed
139 *
140 * @param[in] ctx - pldm_msgbuf context for extractor
141 *
142 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
143 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
144 * indicates that an incorrect sequence of accesses have occurred, and
145 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
146 * pointer.
147 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300148LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300149LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930150{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930151 if (ctx->remaining != 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930152 return -EBADMSG;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930153 }
154
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930155 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930156}
157
158/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030159 * @brief Destroy the pldm buf
160 *
161 * @param[in] ctx - pldm_msgbuf context for extractor
162 *
163 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
164 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
165 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
166 * bounds of the buffer.
167 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300168LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300169LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030170{
171 int valid;
172
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030173 valid = pldm_msgbuf_validate(ctx);
174
175 ctx->cursor = NULL;
176 ctx->remaining = 0;
177
178 return valid;
179}
180
181/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930182 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
183 * has been completely consumed without overflow
184 *
185 * @param[in] ctx - pldm_msgbuf context
186 *
187 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
188 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
189 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
190 * have occurred byond the bounds of the buffer
191 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300192LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300193LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +0930194pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930195{
196 int consumed;
197
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930198 consumed = pldm_msgbuf_consumed(ctx);
199
200 ctx->cursor = NULL;
201 ctx->remaining = 0;
202
203 return consumed;
204}
205
Andrew Jeffery66c77232024-04-24 11:42:02 +0930206/*
207 * Exploit the pre-processor to perform type checking by macro substitution.
208 *
209 * A C type is defined by its alignment as well as its object
210 * size, and compilers have a hammer to enforce it in the form of
211 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
212 * the libpldm public API this presents a problem: Naively attempting to use the
213 * msgbuf APIs on a member of a packed struct would yield an error.
214 *
215 * The msgbuf APIs are implemented such that data is moved through unaligned
216 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
217 * make the object pointers take a trip through `void *` at its API boundary.
218 * That presents a bit too much of an opportunity to non-surgically remove your
219 * own foot, so here we set about doing something to mitigate that as well.
220 *
221 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
222 * only for the purpose of object sizes, disregarding alignment. We have a few
223 * constraints that cause some headaches:
224 *
225 * 1. We have to perform the type-check before a call through a C function,
226 * as the function must take the object pointer argument as `void *`.
227 * Essentially, this constrains us to doing something with macros.
228 *
229 * 2. While libpldm is a C library, its test suite is written in C++ to take
230 * advantage of gtest.
231 *
232 * 3. Ideally we'd do something with C's `static_assert()`, however
233 * `static_assert()` is defined as void, and as we're constrained to macros,
234 * using `static_assert()` would require a statement-expression
235 *
236 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
237 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
238 * the purpose of enabling statement-expressions in this one instance.
239 *
240 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
241 * however it's implemented in terms of `_Generic()`, which is not available
242 * in C++.
243 *
244 * Combined this means we need separate solutions for C and C++.
245 *
246 * For C, as we don't have statement-expressions, we need to exploit some other
247 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
248 * API function call. We also have to take care of the fact that the call-sites
249 * may be in the context of a variable assignment for error-handling purposes.
250 * The key observation is that we can use the comma operator as a sequence point
251 * to order the type check before the API call, discarding the "result" value of
252 * the type check and yielding the return value of the API call.
253 *
254 * C++ could be less of a headache than the C as we can leverage template
255 * functions. An advantage of template functions is that while their definition
256 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530257 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930258 * we have in the C path. However, the use of the msgbuf APIs in the test suite
259 * still makes things somewhat tricky, as the call-sites in the test suite are
260 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
261 * takes both the object type and the required type as template arguments, and
262 * then define the object pointer parameter as `void *` for a call through to
263 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
264 * encapsulated in gtest macros, use of commas in the template specification
265 * causes pre-processor confusion. In this way we're constrained to only one
266 * template argument per function.
267 *
268 * Implement the C++ path using template functions that take the destination
269 * object type as a template argument, while the name of the function symbols
270 * are derived from the required type. The manual implementations of these
271 * appear at the end of the header. The type safety is actually enforced
272 * by `static_assert()` this time, as we can use statements as we're not
273 * constrained to an expression in the templated function body.
274 *
275 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
276 * double-evaluation of some arguments. We're not yet bothered by this for two
277 * reasons:
278 *
279 * 1. The nature of the current call-sites are such that there are no
280 * argument expressions that result in undesirable side-effects
281 *
282 * 2. It's an API internal to the libpldm implementation, and we can fix things
283 * whenever something crops up the violates the observation in 1.
284 */
285#ifdef __cplusplus
286#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
287 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
288#else
289#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
290 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
291#endif
292
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930293/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030294 * @brief pldm_msgbuf extractor for a uint8_t
295 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530296 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030297 * @param[out] dst - destination of extracted value
298 *
299 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
300 * PLDM_ERROR_INVALID_LENGTH otherwise.
301 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
302 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930303#define pldm_msgbuf_extract_uint8(ctx, dst) \
304 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930305 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300306LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300307LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930308// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930309pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030310{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300311 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930312 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030313 }
314
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930315 if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
316 memcpy(dst, ctx->cursor, sizeof(uint8_t));
317 ctx->cursor++;
318 ctx->remaining -= sizeof(uint8_t);
319 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030320 }
321
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930322 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
323 ctx->remaining -= sizeof(uint8_t);
324 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930325
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930326 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030327}
328
Andrew Jeffery66c77232024-04-24 11:42:02 +0930329#define pldm_msgbuf_extract_int8(ctx, dst) \
330 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930331 ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300332LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300333LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930334// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930335pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030336{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300337 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930338 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030339 }
340
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930341 if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
342 memcpy(dst, ctx->cursor, sizeof(int8_t));
343 ctx->cursor++;
344 ctx->remaining -= sizeof(int8_t);
345 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030346 }
347
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930348 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
349 ctx->remaining -= sizeof(int8_t);
350 }
351
352 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030353}
354
Andrew Jeffery66c77232024-04-24 11:42:02 +0930355#define pldm_msgbuf_extract_uint16(ctx, dst) \
356 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930357 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300358LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300359LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930360// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930361pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030362{
363 uint16_t ldst;
364
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300365 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930366 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030367 }
368
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930369 // Check for underflow while tracking the magnitude of the buffer overflow
370 static_assert(
371 // NOLINTNEXTLINE(bugprone-sizeof-expression)
372 sizeof(ldst) < INTMAX_MAX,
373 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930374
375 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
376 // Use memcpy() to have the compiler deal with any alignment
377 // issues on the target architecture
378 memcpy(&ldst, ctx->cursor, sizeof(ldst));
379
380 // Only assign the target value once it's correctly decoded
381 ldst = le16toh(ldst);
382
383 // Allow storing to unaligned
384 memcpy(dst, &ldst, sizeof(ldst));
385
386 ctx->cursor += sizeof(ldst);
387 ctx->remaining -= sizeof(ldst);
388 return 0;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930389 }
390
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930391 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
392 ctx->remaining -= sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030393 }
394
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930395 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030396}
397
Andrew Jeffery66c77232024-04-24 11:42:02 +0930398#define pldm_msgbuf_extract_int16(ctx, dst) \
399 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930400 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300401LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300402LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930403// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930404pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030405{
406 int16_t ldst;
407
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300408 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930409 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030410 }
411
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930412 static_assert(
413 // NOLINTNEXTLINE(bugprone-sizeof-expression)
414 sizeof(ldst) < INTMAX_MAX,
415 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930416
417 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
418 memcpy(&ldst, ctx->cursor, sizeof(ldst));
419 ldst = le16toh(ldst);
420 memcpy(dst, &ldst, sizeof(ldst));
421 ctx->cursor += sizeof(ldst);
422 ctx->remaining -= sizeof(ldst);
423 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030424 }
425
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930426 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
427 ctx->remaining -= sizeof(ldst);
428 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030429
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930430 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030431}
432
Andrew Jeffery66c77232024-04-24 11:42:02 +0930433#define pldm_msgbuf_extract_uint32(ctx, dst) \
434 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930435 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300436LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300437LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930438// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930439pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030440{
441 uint32_t ldst;
442
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300443 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930444 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030445 }
446
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930447 static_assert(
448 // NOLINTNEXTLINE(bugprone-sizeof-expression)
449 sizeof(ldst) < INTMAX_MAX,
450 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930451
452 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
453 memcpy(&ldst, ctx->cursor, sizeof(ldst));
454 ldst = le32toh(ldst);
455 memcpy(dst, &ldst, sizeof(ldst));
456 ctx->cursor += sizeof(ldst);
457 ctx->remaining -= sizeof(ldst);
458 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030459 }
460
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930461 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
462 ctx->remaining -= sizeof(ldst);
463 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030464
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930465 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030466}
467
Andrew Jeffery66c77232024-04-24 11:42:02 +0930468#define pldm_msgbuf_extract_int32(ctx, dst) \
469 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930470 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300471LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300472LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930473// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930474pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030475{
476 int32_t ldst;
477
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300478 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930479 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030480 }
481
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930482 static_assert(
483 // NOLINTNEXTLINE(bugprone-sizeof-expression)
484 sizeof(ldst) < INTMAX_MAX,
485 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930486
487 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
488 memcpy(&ldst, ctx->cursor, sizeof(ldst));
489 ldst = le32toh(ldst);
490 memcpy(dst, &ldst, sizeof(ldst));
491 ctx->cursor += sizeof(ldst);
492 ctx->remaining -= sizeof(ldst);
493 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030494 }
495
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930496 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
497 ctx->remaining -= sizeof(ldst);
498 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030499
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930500 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030501}
502
Andrew Jeffery66c77232024-04-24 11:42:02 +0930503#define pldm_msgbuf_extract_real32(ctx, dst) \
504 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930505 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300506LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300507LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930508// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930509pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030510{
511 uint32_t ldst;
512
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930513 static_assert(sizeof(real32_t) == sizeof(ldst),
514 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930515
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300516 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930517 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030518 }
519
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930520 static_assert(
521 // NOLINTNEXTLINE(bugprone-sizeof-expression)
522 sizeof(ldst) < INTMAX_MAX,
523 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930524
525 if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
526 memcpy(&ldst, ctx->cursor, sizeof(ldst));
527 ldst = le32toh(ldst);
528 memcpy(dst, &ldst, sizeof(ldst));
529 ctx->cursor += sizeof(ldst);
530 ctx->remaining -= sizeof(ldst);
531 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030532 }
533
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930534 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
535 ctx->remaining -= sizeof(ldst);
536 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030537
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930538 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030539}
540
Andrew Jeffery66c77232024-04-24 11:42:02 +0930541/**
542 * Extract the field at the msgbuf cursor into the lvalue named by dst.
543 *
544 * @param ctx The msgbuf context object
545 * @param dst The lvalue into which the field at the msgbuf cursor should be
546 * extracted
547 *
548 * @return PLDM_SUCCESS on success, otherwise another value on error
549 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030550#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930551 _Generic((dst), \
552 uint8_t: pldm__msgbuf_extract_uint8, \
553 int8_t: pldm__msgbuf_extract_int8, \
554 uint16_t: pldm__msgbuf_extract_uint16, \
555 int16_t: pldm__msgbuf_extract_int16, \
556 uint32_t: pldm__msgbuf_extract_uint32, \
557 int32_t: pldm__msgbuf_extract_int32, \
558 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
559
560/**
561 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
562 *
563 * @param ctx The msgbuf context object
564 * @param dst The pointer to the object into which the field at the msgbuf
565 * cursor should be extracted
566 *
567 * @return PLDM_SUCCESS on success, otherwise another value on error
568 */
569#define pldm_msgbuf_extract_p(ctx, dst) \
570 _Generic((dst), \
571 uint8_t *: pldm__msgbuf_extract_uint8, \
572 int8_t *: pldm__msgbuf_extract_int8, \
573 uint16_t *: pldm__msgbuf_extract_uint16, \
574 int16_t *: pldm__msgbuf_extract_int16, \
575 uint32_t *: pldm__msgbuf_extract_uint32, \
576 int32_t *: pldm__msgbuf_extract_int32, \
577 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030578
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000579/**
580 * @ref pldm_msgbuf_extract_array
581 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300582LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000583LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300584LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930585// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000586pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
587 void *dst, size_t dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930588{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300589 if (!ctx->cursor || count > dst_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930590 return -EINVAL;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930591 }
592
593 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930594 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930595 }
596
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930597#if INTMAX_MAX < SIZE_MAX
598 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930599 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930600 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930601#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930602
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930603 if (ctx->remaining >= (intmax_t)count) {
604 memcpy(dst, ctx->cursor, count);
605 ctx->cursor += count;
606 ctx->remaining -= (intmax_t)count;
607 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930608 }
609
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930610 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
611 ctx->remaining -= (intmax_t)count;
612 }
Andrew Jeffery369b1212023-04-20 15:44:48 +0930613
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930614 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930615}
616
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000617/**
618 * @ref pldm_msgbuf_extract_array
619 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300620LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000621LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300622LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000623pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
624 size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930625{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000626 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930627}
628
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000629/**
630 * @ref pldm_msgbuf_extract_array
631 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300632LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000633LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300634LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000635pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
636 uint8_t *dst, size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930637{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000638 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930639}
640
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000641/**
642 * Extract an array of data from the msgbuf instance
643 *
644 * @param ctx - The msgbuf instance from which to extract an array of data
645 * @param count - The number of array elements to extract
646 * @param dst - The array object into which elements from @p ctx should be
647 extracted
648 * @param dst_count - The maximum number of elements to place into @p dst
649 *
650 * Note that both @p count and @p dst_count can only be counted by `sizeof` for
651 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
652 * of array elements and _not_ the object size of the array.
653 */
654#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930655 _Generic((*(dst)), \
656 uint8_t: pldm_msgbuf_extract_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000657 char: pldm_msgbuf_extract_array_char)(ctx, count, dst, \
658 dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930659
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300660LIBPLDM_CC_NONNULL
Matt Johnstone8d8d332024-10-28 17:13:32 +0800661LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint64(struct pldm_msgbuf *ctx,
662 const uint64_t src)
663{
664 uint64_t val = htole64(src);
665
666 if (!ctx->cursor) {
667 return -EINVAL;
668 }
669
670 static_assert(
671 // NOLINTNEXTLINE(bugprone-sizeof-expression)
672 sizeof(src) < INTMAX_MAX,
673 "The following addition may not uphold the runtime assertion");
674
675 if (ctx->remaining >= (intmax_t)sizeof(src)) {
676 memcpy(ctx->cursor, &val, sizeof(val));
677 ctx->cursor += sizeof(src);
678 ctx->remaining -= sizeof(src);
679 return 0;
680 }
681
682 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
683 ctx->remaining -= sizeof(src);
684 }
685
686 return -EOVERFLOW;
687}
688
689LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300690LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
691 const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700692{
693 uint32_t val = htole32(src);
694
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930695 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930696 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700697 }
698
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930699 static_assert(
700 // NOLINTNEXTLINE(bugprone-sizeof-expression)
701 sizeof(src) < INTMAX_MAX,
702 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930703
704 if (ctx->remaining >= (intmax_t)sizeof(src)) {
705 memcpy(ctx->cursor, &val, sizeof(val));
706 ctx->cursor += sizeof(src);
707 ctx->remaining -= sizeof(src);
708 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700709 }
710
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930711 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
712 ctx->remaining -= sizeof(src);
713 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700714
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930715 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700716}
717
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300718LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300719LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
720 const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700721{
722 uint16_t val = htole16(src);
723
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930724 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930725 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700726 }
727
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930728 static_assert(
729 // NOLINTNEXTLINE(bugprone-sizeof-expression)
730 sizeof(src) < INTMAX_MAX,
731 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930732
733 if (ctx->remaining >= (intmax_t)sizeof(src)) {
734 memcpy(ctx->cursor, &val, sizeof(val));
735 ctx->cursor += sizeof(src);
736 ctx->remaining -= sizeof(src);
737 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700738 }
739
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930740 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
741 ctx->remaining -= sizeof(src);
742 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700743
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930744 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700745}
746
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300747LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300748LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
749 const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700750{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930751 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930752 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700753 }
754
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930755 static_assert(
756 // NOLINTNEXTLINE(bugprone-sizeof-expression)
757 sizeof(src) < INTMAX_MAX,
758 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930759
760 if (ctx->remaining >= (intmax_t)sizeof(src)) {
761 memcpy(ctx->cursor, &src, sizeof(src));
762 ctx->cursor += sizeof(src);
763 ctx->remaining -= sizeof(src);
764 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700765 }
766
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930767 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
768 ctx->remaining -= sizeof(src);
769 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700770
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930771 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700772}
773
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300774LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300775LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
776 const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700777{
778 int32_t val = htole32(src);
779
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930780 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930781 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700782 }
783
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930784 static_assert(
785 // NOLINTNEXTLINE(bugprone-sizeof-expression)
786 sizeof(src) < INTMAX_MAX,
787 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930788
789 if (ctx->remaining >= (intmax_t)sizeof(src)) {
790 memcpy(ctx->cursor, &val, sizeof(val));
791 ctx->cursor += sizeof(src);
792 ctx->remaining -= sizeof(src);
793 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700794 }
795
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930796 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
797 ctx->remaining -= sizeof(src);
798 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700799
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930800 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700801}
802
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300803LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300804LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
805 const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700806{
807 int16_t val = htole16(src);
808
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930809 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930810 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700811 }
812
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930813 static_assert(
814 // NOLINTNEXTLINE(bugprone-sizeof-expression)
815 sizeof(src) < INTMAX_MAX,
816 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930817
818 if (ctx->remaining >= (intmax_t)sizeof(src)) {
819 memcpy(ctx->cursor, &val, sizeof(val));
820 ctx->cursor += sizeof(src);
821 ctx->remaining -= sizeof(src);
822 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700823 }
824
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930825 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
826 ctx->remaining -= sizeof(src);
827 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700828
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930829 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700830}
831
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300832LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300833LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
834 const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700835{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930836 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930837 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700838 }
839
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930840 static_assert(
841 // NOLINTNEXTLINE(bugprone-sizeof-expression)
842 sizeof(src) < INTMAX_MAX,
843 "The following addition may not uphold the runtime assertion");
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930844
845 if (ctx->remaining >= (intmax_t)sizeof(src)) {
846 memcpy(ctx->cursor, &src, sizeof(src));
847 ctx->cursor += sizeof(src);
848 ctx->remaining -= sizeof(src);
849 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700850 }
851
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930852 if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
853 ctx->remaining -= sizeof(src);
854 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700855
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930856 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700857}
858
859#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930860 _Generic((src), \
861 uint8_t: pldm_msgbuf_insert_uint8, \
862 int8_t: pldm_msgbuf_insert_int8, \
863 uint16_t: pldm_msgbuf_insert_uint16, \
864 int16_t: pldm_msgbuf_insert_int16, \
865 uint32_t: pldm_msgbuf_insert_uint32, \
Matt Johnstone8d8d332024-10-28 17:13:32 +0800866 int32_t: pldm_msgbuf_insert_int32, \
867 uint64_t: pldm_msgbuf_insert_uint64)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700868
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000869/**
870 * @ref pldm_msgbuf_insert_array
871 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300872LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000873LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300874LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930875// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000876pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
877 const void *src, size_t src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700878{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300879 if (!ctx->cursor || count > src_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930880 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700881 }
882
883 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930884 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700885 }
886
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930887#if INTMAX_MAX < SIZE_MAX
888 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930889 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700890 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930891#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700892
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930893 if (ctx->remaining >= (intmax_t)count) {
894 memcpy(ctx->cursor, src, count);
895 ctx->cursor += count;
896 ctx->remaining -= (intmax_t)count;
897 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700898 }
899
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930900 if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
901 ctx->remaining -= (intmax_t)count;
902 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700903
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930904 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700905}
906
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000907/**
908 * @ref pldm_msgbuf_insert_array
909 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300910LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000911LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300912LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000913pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
914 const char *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930915{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000916 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930917}
918
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000919/**
920 * @ref pldm_msgbuf_insert_array
921 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300922LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000923LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300924LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000925pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
926 const uint8_t *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930927{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000928 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930929}
930
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000931/**
932 * Insert an array of data into the msgbuf instance
933 *
934 * @param ctx - The msgbuf instance into which the array of data should be
935 * inserted
936 * @param count - The number of array elements to insert
937 * @param src - The array object from which elements should be inserted into
938 @p ctx
939 * @param src_count - The maximum number of elements to insert from @p src
940 *
941 * Note that both @p count and @p src_count can only be counted by `sizeof` for
942 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
943 * of array elements and _not_ the object size of the array.
944 */
945#define pldm_msgbuf_insert_array(dst, count, src, src_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930946 _Generic((*(src)), \
947 uint8_t: pldm_msgbuf_insert_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000948 char: pldm_msgbuf_insert_array_char)(dst, count, src, \
949 src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700950
Varsha Kaverappa79393822024-08-07 00:40:13 -0500951LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300952LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
953 size_t required,
954 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700955{
Varsha Kaverappa79393822024-08-07 00:40:13 -0500956 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930957 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700958 }
959
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930960#if INTMAX_MAX < SIZE_MAX
961 if (required > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930962 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700963 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930964#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700965
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930966 if (ctx->remaining >= (intmax_t)required) {
967 if (cursor) {
968 *cursor = ctx->cursor;
969 }
970 ctx->cursor += required;
971 ctx->remaining -= (intmax_t)required;
972 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700973 }
974
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930975 if (ctx->remaining >= INTMAX_MIN + (intmax_t)required) {
976 ctx->remaining -= (intmax_t)required;
Varsha Kaverappa79393822024-08-07 00:40:13 -0500977 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700978
Andrew Jeffery4f60fb72024-09-23 13:56:44 +0930979 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700980}
981
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300982LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300983LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen9c83d682024-07-02 08:43:09 +0000984pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
985 size_t *length)
986{
987 intmax_t measured;
988
Thu Nguyen9c83d682024-07-02 08:43:09 +0000989 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930990 return -EINVAL;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000991 }
992
993 if (ctx->remaining < 0) {
994 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930995 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000996 }
997
998 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
999 if (measured == ctx->remaining) {
1000 /*
1001 * We have hit the end of the buffer prior to the NUL terminator.
1002 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
1003 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1004 * return an error.
1005 */
1006 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301007 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001008 }
1009
1010 /* Include the NUL terminator in the span length, as spans are opaque */
1011 measured++;
1012
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301013 if (ctx->remaining >= measured) {
1014 if (cursor) {
1015 *cursor = ctx->cursor;
1016 }
1017
1018 ctx->cursor += measured;
1019
1020 if (length) {
1021 *length = measured;
1022 }
1023
1024 ctx->remaining -= measured;
1025 return 0;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001026 }
1027
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301028 if (ctx->remaining >= INTMAX_MIN + measured) {
1029 ctx->remaining -= measured;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001030 }
1031
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301032 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001033}
1034
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001035LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001036LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen15237782024-07-02 09:30:41 +00001037pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1038 size_t *length)
1039{
1040 static const char16_t term = 0;
1041 ptrdiff_t measured;
1042 void *end;
1043
Thu Nguyen15237782024-07-02 09:30:41 +00001044 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301045 return -EINVAL;
Thu Nguyen15237782024-07-02 09:30:41 +00001046 }
1047
1048 if (ctx->remaining < 0) {
1049 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301050 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001051 }
1052
1053 /*
1054 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1055 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1056 * start of the string
1057 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301058 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001059 do {
1060 if (end != ctx->cursor) {
1061 /*
1062 * If we've looped we've found a relatively-unaligned NUL code-point.
1063 * Scan again from a relatively-aligned start point.
1064 */
1065 end = (char *)end + 1;
1066 }
1067 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301068 end = memmem(end, ctx->remaining - measured, &term,
1069 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001070 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1071
1072 if (!end) {
1073 /*
1074 * Optimistically, the last required pattern byte was one beyond the end of
1075 * the buffer. Setting ctx->remaining negative ensures the
1076 * `pldm_msgbuf_destroy*()` APIs also return an error.
1077 */
1078 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301079 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001080 }
1081
1082 end = (char *)end + sizeof(char16_t);
1083 measured = (char *)end - (char *)ctx->cursor;
1084
1085#if INTMAX_MAX < PTRDIFF_MAX
1086 if (measured >= INTMAX_MAX) {
1087 return pldm_msgbuf_status(ctx, EOVERFLOW);
1088 }
1089#endif
1090
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301091 if (ctx->remaining >= (intmax_t)measured) {
1092 if (cursor) {
1093 *cursor = ctx->cursor;
1094 }
1095
1096 ctx->cursor += measured;
1097
1098 if (length) {
1099 *length = (size_t)measured;
1100 }
1101
1102 ctx->remaining -= (intmax_t)measured;
1103 return 0;
Thu Nguyen15237782024-07-02 09:30:41 +00001104 }
1105
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301106 if (ctx->remaining >= INTMAX_MIN + (intmax_t)measured) {
1107 ctx->remaining -= (intmax_t)measured;
Thu Nguyen15237782024-07-02 09:30:41 +00001108 }
1109
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301110 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001111}
1112
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001113LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001114LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301115pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001116{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001117 if (!ctx->cursor || *cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301118 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +07001119 }
1120
Thu Nguyen062c8762023-04-22 20:45:04 +07001121 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301122 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +07001123 }
1124
1125 *cursor = ctx->cursor;
1126 ctx->cursor += ctx->remaining;
1127 *len = ctx->remaining;
1128 ctx->remaining = 0;
1129
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301130 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001131}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001132
1133/**
Matt Johnston5d4f7b52024-12-12 14:03:57 +08001134 * Return the number of bytes used in a msgbuf instance.
1135 *
1136 * @param ctx - The msgbuf.
1137 * @param orig_len - The original size of the msgbuf, the `len` argument passed to
1138 * pldm_msgbuf_init_errno().
1139 * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
1140 *
1141 * This can be called after a number of pldm_msgbuf_insert...() calls to
1142 * determine the total size that was written.
1143 *
1144 */
1145LIBPLDM_CC_NONNULL
1146LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy_used(struct pldm_msgbuf *ctx,
1147 size_t orig_len,
1148 size_t *ret_used_len)
1149{
1150 int rc;
1151 rc = pldm_msgbuf_validate(ctx);
1152 if (rc) {
1153 return rc;
1154 }
1155
1156 if ((size_t)ctx->remaining > orig_len) {
1157 /* Caller passed incorrect orig_len */
1158 return -EOVERFLOW;
1159 }
1160
1161 *ret_used_len = orig_len - ctx->remaining;
1162 return 0;
1163}
1164
1165/**
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001166 * @brief pldm_msgbuf copy data between two msg buffers
1167 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301168 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1169 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001170 * @param[in] size - size of data to be copied
1171 * @param[in] description - description of data copied
1172 *
1173 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1174 * PLDM_ERROR_INVALID_LENGTH otherwise.
1175 * PLDM_ERROR_INVALID_DATA if input is invalid
1176 */
1177#define pldm_msgbuf_copy(dst, src, type, name) \
1178 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001179LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001180LIBPLDM_CC_ALWAYS_INLINE int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001181// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301182pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001183 const char *description LIBPLDM_CC_UNUSED)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001184{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001185 if (!src->cursor || !dst->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301186 return -EINVAL;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001187 }
1188
1189#if INTMAX_MAX < SIZE_MAX
1190 if (size > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301191 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001192 }
1193#endif
1194
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301195 if (src->remaining >= (intmax_t)size &&
1196 dst->remaining >= (intmax_t)size) {
1197 memcpy(dst->cursor, src->cursor, size);
1198 src->cursor += size;
1199 src->remaining -= (intmax_t)size;
1200 dst->cursor += size;
1201 dst->remaining -= (intmax_t)size;
1202 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001203 }
1204
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301205 if (src->remaining >= INTMAX_MIN + (intmax_t)size) {
1206 src->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001207 }
1208
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301209 if (dst->remaining >= INTMAX_MIN + (intmax_t)size) {
1210 dst->remaining -= (intmax_t)size;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001211 }
1212
Andrew Jeffery4f60fb72024-09-23 13:56:44 +09301213 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001214}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301215
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001216LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001217LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001218LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery8b879602024-07-08 12:50:19 +09301219pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1220{
1221 void *ascii = NULL;
1222 size_t len = 0;
1223 int rc;
1224
1225 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1226 if (rc < 0) {
1227 return rc;
1228 }
1229
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001230 return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
Andrew Jeffery8b879602024-07-08 12:50:19 +09301231}
1232
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001233LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001234LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001235LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301236pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1237{
1238 void *utf16 = NULL;
1239 size_t len = 0;
1240 int rc;
1241
1242 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1243 if (rc < 0) {
1244 return rc;
1245 }
1246
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001247 return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301248}
1249
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301250#ifdef __cplusplus
1251}
1252#endif
1253
Andrew Jeffery66c77232024-04-24 11:42:02 +09301254#ifdef __cplusplus
1255#include <type_traits>
1256
1257template <typename T>
1258static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1259 void *buf)
1260{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301261 static_assert(std::is_same<uint8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301262 return pldm__msgbuf_extract_uint8(ctx, buf);
1263}
1264
1265template <typename T>
1266static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1267 void *buf)
1268{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301269 static_assert(std::is_same<int8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301270 return pldm__msgbuf_extract_int8(ctx, buf);
1271}
1272
1273template <typename T>
1274static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1275 void *buf)
1276{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301277 static_assert(std::is_same<uint16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301278 return pldm__msgbuf_extract_uint16(ctx, buf);
1279}
1280
1281template <typename T>
1282static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1283 void *buf)
1284{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301285 static_assert(std::is_same<int16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301286 return pldm__msgbuf_extract_int16(ctx, buf);
1287}
1288
1289template <typename T>
1290static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1291 void *buf)
1292{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301293 static_assert(std::is_same<uint32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301294 return pldm__msgbuf_extract_uint32(ctx, buf);
1295}
1296
1297template <typename T>
1298static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1299 void *buf)
1300{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301301 static_assert(std::is_same<int32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301302 return pldm__msgbuf_extract_int32(ctx, buf);
1303}
1304
1305template <typename T>
1306static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1307 void *buf)
1308{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301309 static_assert(std::is_same<real32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301310 return pldm__msgbuf_extract_real32(ctx, buf);
1311}
1312#endif
1313
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301314#endif /* BUF_H */