blob: c2c02feaa00efbaf542fbc2d3cdad38859cf2585 [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 Jeffery66c77232024-04-24 11:42:02 +09305/*
6 * Historically, many of the structs exposed in libpldm's public headers are
7 * defined with __attribute__((packed)). This is unfortunate: it gives the
8 * impression that a wire-format buffer can be cast to the message type to make
9 * the message's fields easily accessible. As it turns out, that's not
10 * that's valid for several reasons:
11 *
12 * 1. Casting the wire-format buffer to a struct of the message type doesn't
13 * abstract the endianness of message field values
14 *
15 * 2. Some messages contain packed tagged union fields which cannot be properly
16 * described in a C struct.
17 *
18 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
19 * that is type-safe, spatially memory-safe, endian-safe, performant, and
20 * free of undefined-behaviour. Message structs that are added to the public
21 * library API should no-longer be marked __attribute__((packed)), and the
22 * implementation of their encode and decode functions must exploit the msgbuf
23 * API.
24 *
25 * However, we would like to allow implementation of codec functions in terms of
26 * msgbuf APIs even if they're decoding a message into a (historically) packed
27 * struct. Some of the complexity that follows is a consequence of the packed/
28 * unpacked conflict.
29 */
30
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103031#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093032/*
33 * Fix up C11's _Static_assert() vs C++'s static_assert().
34 *
35 * Can we please have nice things for once.
36 */
37// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
38#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103039extern "C" {
40#endif
41
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103042#include <libpldm/base.h>
43#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103044
Andrew Jeffery66c77232024-04-24 11:42:02 +093045#include "compiler.h"
46
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103047#include <assert.h>
48#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093049#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103050#include <limits.h>
51#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093052#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103053#include <string.h>
54#include <sys/types.h>
Thu Nguyen15237782024-07-02 09:30:41 +000055#include <uchar.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103056
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093057/*
58 * We can't use static_assert() outside of some other C construct. Deal
59 * with high-level global assertions by burying them in an unused struct
60 * declaration, that has a sole member for compliance with the requirement that
61 * types must have a size.
62*/
63static struct {
64 static_assert(
65 INTMAX_MAX != SIZE_MAX,
66 "Extraction and insertion value comparisons may be broken");
67 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
68 "Extraction and insertion arithmetic may be broken");
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093069 static_assert(PLDM_SUCCESS == 0, "Error handling is broken");
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093070 int compliance;
71} build_assertions __attribute__((unused));
72
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093073enum pldm_msgbuf_error_mode {
74 PLDM_MSGBUF_PLDM_CC = 0x5a,
75 PLDM_MSGBUF_C_ERRNO = 0xa5,
76};
77
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103078struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070079 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093080 intmax_t remaining;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093081 enum pldm_msgbuf_error_mode mode;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103082};
83
Andrew Jefferyd861a682024-06-03 21:43:09 +093084/**
85 * @brief Either negate an errno value or return a value mapped to a PLDM
86 * completion code.
87 *
88 * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API
89 * for ergonomics. It's preferred that we don't try to unify this with
90 * `pldm_xlate_errno()` from src/api.h despite the similarities.
91 *
92 * @param[in] ctx - The msgbuf context providing the personality info
93 * @param[in] err - The positive errno value to translate
94 *
95 * @return Either the negated value of @p err if the context's error mode is
96 * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the
97 * error mode is `PLDM_MSGBUF_PLDM_CC`.
98 */
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093099__attribute__((always_inline)) static inline int
100pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err)
101{
102 int rc;
103
104 assert(err != 0);
105 assert(err <= INT_MAX);
106
107 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
108 if (err > INT_MAX) {
109 return -EINVAL;
110 }
111
112 static_assert(INT_MIN + INT_MAX < 0,
113 "Arithmetic assumption failure");
114 return -((int)err);
115 }
116
117 if (err > INT_MAX) {
118 return PLDM_ERROR;
119 }
120
121 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
122 switch (err) {
123 case EINVAL:
124 rc = PLDM_ERROR_INVALID_DATA;
125 break;
126 case EBADMSG:
127 case EOVERFLOW:
128 rc = PLDM_ERROR_INVALID_LENGTH;
129 break;
130 default:
131 assert(false);
132 rc = PLDM_ERROR;
133 break;
134 }
135
136 assert(rc > 0);
137 return rc;
138}
139
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030140/**
141 * @brief Initialize pldm buf struct for buf extractor
142 *
143 * @param[out] ctx - pldm_msgbuf context for extractor
144 * @param[in] minsize - The minimum required length of buffer `buf`
145 * @param[in] buf - buffer to be extracted
146 * @param[in] len - size of buffer
147 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930148 * @return 0 on success, otherwise an error code appropriate for the current
149 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030150 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930151__attribute__((always_inline)) static inline int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930152// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
153pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
154 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030155{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930156 assert(ctx);
157 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
158 ctx->mode == PLDM_MSGBUF_C_ERRNO);
159
160 if (!buf) {
161 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030162 }
163
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930164 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930165 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030166 }
167
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930168#if INTMAX_MAX < SIZE_MAX
169 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930170 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930171 }
172#endif
173
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930174 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930175 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030176 }
177
178 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930179 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030180
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930181 return 0;
182}
183
184/**
185 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
186 *
187 * @see pldm__msgbuf_init
188 *
189 * @param[out] ctx - pldm_msgbuf context for extractor
190 * @param[in] minsize - The minimum required length of buffer `buf`
191 * @param[in] buf - buffer to be extracted
192 * @param[in] len - size of buffer
193 *
194 * @return PLDM_SUCCESS if the provided buffer region is sensible,
195 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
196 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
197 */
198__attribute__((always_inline)) static inline int
199pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
200 size_t len)
201{
202 if (!ctx) {
203 return PLDM_ERROR_INVALID_DATA;
204 }
205
206 ctx->mode = PLDM_MSGBUF_PLDM_CC;
207 return pldm__msgbuf_init(ctx, minsize, buf, len);
208}
209
210/**
211 * @brief Initialise a msgbuf instance to return errors as negative errno values
212 *
213 * @see pldm__msgbuf_init
214 *
215 * @param[out] ctx - pldm_msgbuf context for extractor
216 * @param[in] minsize - The minimum required length of buffer `buf`
217 * @param[in] buf - buffer to be extracted
218 * @param[in] len - size of buffer
219 *
220 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
221 * pointer parameters are invalid, or -EOVERFLOW if length constraints
222 * are violated.
223 */
224__attribute__((always_inline)) static inline int
225pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
226 size_t len)
227{
228 if (!ctx) {
229 return -EINVAL;
230 }
231
232 ctx->mode = PLDM_MSGBUF_C_ERRNO;
233 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030234}
235
236/**
237 * @brief Validate buffer overflow state
238 *
239 * @param[in] ctx - pldm_msgbuf context for extractor
240 *
241 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
242 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
243 * prior accesses would have occurred beyond the bounds of the buffer, and
244 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
245 * pointer.
246 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930247__attribute__((always_inline)) static inline int
248pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030249{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930250 assert(ctx);
251 if (ctx->remaining < 0) {
252 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030253 }
254
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930255 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030256}
257
258/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930259 * @brief Test whether a message buffer has been exactly consumed
260 *
261 * @param[in] ctx - pldm_msgbuf context for extractor
262 *
263 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
264 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
265 * indicates that an incorrect sequence of accesses have occurred, and
266 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
267 * pointer.
268 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930269__attribute__((always_inline)) static inline int
270pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930271{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930272 assert(ctx);
273 if (ctx->remaining != 0) {
274 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930275 }
276
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930277 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930278}
279
280/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030281 * @brief Destroy the pldm buf
282 *
283 * @param[in] ctx - pldm_msgbuf context for extractor
284 *
285 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
286 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
287 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
288 * bounds of the buffer.
289 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930290__attribute__((always_inline)) static inline int
291pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030292{
293 int valid;
294
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930295 assert(ctx);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030296 valid = pldm_msgbuf_validate(ctx);
297
298 ctx->cursor = NULL;
299 ctx->remaining = 0;
300
301 return valid;
302}
303
304/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930305 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
306 * has been completely consumed without overflow
307 *
308 * @param[in] ctx - pldm_msgbuf context
309 *
310 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
311 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
312 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
313 * have occurred byond the bounds of the buffer
314 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930315__attribute__((always_inline)) static inline int
316pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930317{
318 int consumed;
319
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930320 assert(ctx);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930321 consumed = pldm_msgbuf_consumed(ctx);
322
323 ctx->cursor = NULL;
324 ctx->remaining = 0;
325
326 return consumed;
327}
328
Andrew Jeffery66c77232024-04-24 11:42:02 +0930329/*
330 * Exploit the pre-processor to perform type checking by macro substitution.
331 *
332 * A C type is defined by its alignment as well as its object
333 * size, and compilers have a hammer to enforce it in the form of
334 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
335 * the libpldm public API this presents a problem: Naively attempting to use the
336 * msgbuf APIs on a member of a packed struct would yield an error.
337 *
338 * The msgbuf APIs are implemented such that data is moved through unaligned
339 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
340 * make the object pointers take a trip through `void *` at its API boundary.
341 * That presents a bit too much of an opportunity to non-surgically remove your
342 * own foot, so here we set about doing something to mitigate that as well.
343 *
344 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
345 * only for the purpose of object sizes, disregarding alignment. We have a few
346 * constraints that cause some headaches:
347 *
348 * 1. We have to perform the type-check before a call through a C function,
349 * as the function must take the object pointer argument as `void *`.
350 * Essentially, this constrains us to doing something with macros.
351 *
352 * 2. While libpldm is a C library, its test suite is written in C++ to take
353 * advantage of gtest.
354 *
355 * 3. Ideally we'd do something with C's `static_assert()`, however
356 * `static_assert()` is defined as void, and as we're constrained to macros,
357 * using `static_assert()` would require a statement-expression
358 *
359 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
360 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
361 * the purpose of enabling statement-expressions in this one instance.
362 *
363 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
364 * however it's implemented in terms of `_Generic()`, which is not available
365 * in C++.
366 *
367 * Combined this means we need separate solutions for C and C++.
368 *
369 * For C, as we don't have statement-expressions, we need to exploit some other
370 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
371 * API function call. We also have to take care of the fact that the call-sites
372 * may be in the context of a variable assignment for error-handling purposes.
373 * The key observation is that we can use the comma operator as a sequence point
374 * to order the type check before the API call, discarding the "result" value of
375 * the type check and yielding the return value of the API call.
376 *
377 * C++ could be less of a headache than the C as we can leverage template
378 * functions. An advantage of template functions is that while their definition
379 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530380 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930381 * we have in the C path. However, the use of the msgbuf APIs in the test suite
382 * still makes things somewhat tricky, as the call-sites in the test suite are
383 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
384 * takes both the object type and the required type as template arguments, and
385 * then define the object pointer parameter as `void *` for a call through to
386 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
387 * encapsulated in gtest macros, use of commas in the template specification
388 * causes pre-processor confusion. In this way we're constrained to only one
389 * template argument per function.
390 *
391 * Implement the C++ path using template functions that take the destination
392 * object type as a template argument, while the name of the function symbols
393 * are derived from the required type. The manual implementations of these
394 * appear at the end of the header. The type safety is actually enforced
395 * by `static_assert()` this time, as we can use statements as we're not
396 * constrained to an expression in the templated function body.
397 *
398 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
399 * double-evaluation of some arguments. We're not yet bothered by this for two
400 * reasons:
401 *
402 * 1. The nature of the current call-sites are such that there are no
403 * argument expressions that result in undesirable side-effects
404 *
405 * 2. It's an API internal to the libpldm implementation, and we can fix things
406 * whenever something crops up the violates the observation in 1.
407 */
408#ifdef __cplusplus
409#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
410 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
411#else
412#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
413 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
414#endif
415
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930416/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030417 * @brief pldm_msgbuf extractor for a uint8_t
418 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530419 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030420 * @param[out] dst - destination of extracted value
421 *
422 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
423 * PLDM_ERROR_INVALID_LENGTH otherwise.
424 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
425 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930426#define pldm_msgbuf_extract_uint8(ctx, dst) \
427 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
428 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930429__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930430// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930431pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030432{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930433 assert(ctx);
434
435 if (!ctx->cursor || !dst) {
436 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030437 }
438
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930439 if (ctx->remaining == INTMAX_MIN) {
440 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930441 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930442 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930443 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030444 assert(ctx->remaining >= 0);
445 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930446 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030447 }
448
Andrew Jeffery66c77232024-04-24 11:42:02 +0930449 memcpy(dst, ctx->cursor, sizeof(uint8_t));
450
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030451 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930452 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030453}
454
Andrew Jeffery66c77232024-04-24 11:42:02 +0930455#define pldm_msgbuf_extract_int8(ctx, dst) \
456 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
457 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930458__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930459// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930460pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030461{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930462 assert(ctx);
463
464 if (!ctx->cursor || !dst) {
465 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030466 }
467
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930468 if (ctx->remaining == INTMAX_MIN) {
469 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930470 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930471 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930472 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030473 assert(ctx->remaining >= 0);
474 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930475 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030476 }
477
Andrew Jeffery66c77232024-04-24 11:42:02 +0930478 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030479 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930480 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030481}
482
Andrew Jeffery66c77232024-04-24 11:42:02 +0930483#define pldm_msgbuf_extract_uint16(ctx, dst) \
484 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
485 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930486__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930487// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930488pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030489{
490 uint16_t ldst;
491
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930492 assert(ctx);
493
494 if (!ctx->cursor || !dst) {
495 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030496 }
497
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930498 // Check for underflow while tracking the magnitude of the buffer overflow
499 static_assert(
500 // NOLINTNEXTLINE(bugprone-sizeof-expression)
501 sizeof(ldst) < INTMAX_MAX,
502 "The following addition may not uphold the runtime assertion");
503 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
504 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930505 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930506 }
507
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030508 // Check for buffer overflow. If we overflow, account for the request as
509 // negative values in ctx->remaining. This way we can debug how far
510 // we've overflowed.
511 ctx->remaining -= sizeof(ldst);
512
513 // Prevent the access if it would overflow. First, assert so we blow up
514 // the test suite right at the point of failure. However, cater to
515 // -DNDEBUG by explicitly testing that the access is valid.
516 assert(ctx->remaining >= 0);
517 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930518 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030519 }
520
521 // Use memcpy() to have the compiler deal with any alignment
522 // issues on the target architecture
523 memcpy(&ldst, ctx->cursor, sizeof(ldst));
524
525 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930526 ldst = le16toh(ldst);
527
528 // Allow storing to unaligned
529 memcpy(dst, &ldst, sizeof(ldst));
530
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030531 ctx->cursor += sizeof(ldst);
532
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930533 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030534}
535
Andrew Jeffery66c77232024-04-24 11:42:02 +0930536#define pldm_msgbuf_extract_int16(ctx, dst) \
537 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
538 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930539__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930540// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930541pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030542{
543 int16_t ldst;
544
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930545 assert(ctx);
546
547 if (!ctx->cursor || !dst) {
548 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030549 }
550
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930551 static_assert(
552 // NOLINTNEXTLINE(bugprone-sizeof-expression)
553 sizeof(ldst) < INTMAX_MAX,
554 "The following addition may not uphold the runtime assertion");
555 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
556 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930557 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930558 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030559 ctx->remaining -= sizeof(ldst);
560 assert(ctx->remaining >= 0);
561 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930562 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030563 }
564
565 memcpy(&ldst, ctx->cursor, sizeof(ldst));
566
Andrew Jeffery66c77232024-04-24 11:42:02 +0930567 ldst = le16toh(ldst);
568 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030569 ctx->cursor += sizeof(ldst);
570
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930571 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030572}
573
Andrew Jeffery66c77232024-04-24 11:42:02 +0930574#define pldm_msgbuf_extract_uint32(ctx, dst) \
575 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
576 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930577__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930578// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930579pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030580{
581 uint32_t ldst;
582
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930583 assert(ctx);
584
585 if (!ctx->cursor || !dst) {
586 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030587 }
588
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930589 static_assert(
590 // NOLINTNEXTLINE(bugprone-sizeof-expression)
591 sizeof(ldst) < INTMAX_MAX,
592 "The following addition may not uphold the runtime assertion");
593 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
594 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930595 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930596 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030597 ctx->remaining -= sizeof(ldst);
598 assert(ctx->remaining >= 0);
599 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930600 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030601 }
602
603 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930604 ldst = le32toh(ldst);
605 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030606 ctx->cursor += sizeof(ldst);
607
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930608 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030609}
610
Andrew Jeffery66c77232024-04-24 11:42:02 +0930611#define pldm_msgbuf_extract_int32(ctx, dst) \
612 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
613 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930614__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930615// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930616pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030617{
618 int32_t ldst;
619
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930620 assert(ctx);
621
622 if (!ctx->cursor || !dst) {
623 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030624 }
625
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930626 static_assert(
627 // NOLINTNEXTLINE(bugprone-sizeof-expression)
628 sizeof(ldst) < INTMAX_MAX,
629 "The following addition may not uphold the runtime assertion");
630 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
631 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930632 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930633 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030634 ctx->remaining -= sizeof(ldst);
635 assert(ctx->remaining >= 0);
636 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930637 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030638 }
639
640 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930641 ldst = le32toh(ldst);
642 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030643 ctx->cursor += sizeof(ldst);
644
645 return PLDM_SUCCESS;
646}
647
Andrew Jeffery66c77232024-04-24 11:42:02 +0930648#define pldm_msgbuf_extract_real32(ctx, dst) \
649 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
650 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930651__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930652// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930653pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030654{
655 uint32_t ldst;
656
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930657 static_assert(sizeof(real32_t) == sizeof(ldst),
658 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930659
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930660 assert(ctx);
661
662 if (!ctx->cursor || !dst) {
663 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030664 }
665
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930666 static_assert(
667 // NOLINTNEXTLINE(bugprone-sizeof-expression)
668 sizeof(ldst) < INTMAX_MAX,
669 "The following addition may not uphold the runtime assertion");
670 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
671 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930672 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930673 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030674 ctx->remaining -= sizeof(ldst);
675 assert(ctx->remaining >= 0);
676 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930677 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030678 }
679
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030680 memcpy(&ldst, ctx->cursor, sizeof(ldst));
681 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930682 memcpy(dst, &ldst, sizeof(ldst));
683 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030684
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930685 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030686}
687
Andrew Jeffery66c77232024-04-24 11:42:02 +0930688/**
689 * Extract the field at the msgbuf cursor into the lvalue named by dst.
690 *
691 * @param ctx The msgbuf context object
692 * @param dst The lvalue into which the field at the msgbuf cursor should be
693 * extracted
694 *
695 * @return PLDM_SUCCESS on success, otherwise another value on error
696 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030697#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930698 _Generic((dst), \
699 uint8_t: pldm__msgbuf_extract_uint8, \
700 int8_t: pldm__msgbuf_extract_int8, \
701 uint16_t: pldm__msgbuf_extract_uint16, \
702 int16_t: pldm__msgbuf_extract_int16, \
703 uint32_t: pldm__msgbuf_extract_uint32, \
704 int32_t: pldm__msgbuf_extract_int32, \
705 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
706
707/**
708 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
709 *
710 * @param ctx The msgbuf context object
711 * @param dst The pointer to the object into which the field at the msgbuf
712 * cursor should be extracted
713 *
714 * @return PLDM_SUCCESS on success, otherwise another value on error
715 */
716#define pldm_msgbuf_extract_p(ctx, dst) \
717 _Generic((dst), \
718 uint8_t *: pldm__msgbuf_extract_uint8, \
719 int8_t *: pldm__msgbuf_extract_int8, \
720 uint16_t *: pldm__msgbuf_extract_uint16, \
721 int16_t *: pldm__msgbuf_extract_int16, \
722 uint32_t *: pldm__msgbuf_extract_uint32, \
723 int32_t *: pldm__msgbuf_extract_int32, \
724 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030725
Andrew Jeffery76712f62024-05-22 15:19:00 +0930726__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930727// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
728pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, void *dst,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930729 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930730{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930731 assert(ctx);
732
733 if (!ctx->cursor || !dst) {
734 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930735 }
736
737 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930738 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930739 }
740
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930741#if INTMAX_MAX < SIZE_MAX
742 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930743 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930744 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930745#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930746
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930747 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930748 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930749 }
750 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930751 assert(ctx->remaining >= 0);
752 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930753 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930754 }
755
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030756 memcpy(dst, ctx->cursor, count);
757 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930758
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930759 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930760}
761
Andrew Jeffery1c571442024-07-08 10:25:48 +0930762__attribute__((always_inline)) static inline int
763pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, char *dst, size_t count)
764{
765 return pldm__msgbuf_extract_array_void(ctx, dst, count);
766}
767
768__attribute__((always_inline)) static inline int
769pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
770 size_t count)
771{
772 return pldm__msgbuf_extract_array_void(ctx, dst, count);
773}
774
Andrew Jeffery369b1212023-04-20 15:44:48 +0930775#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930776 _Generic((*(dst)), \
777 uint8_t: pldm_msgbuf_extract_array_uint8, \
778 char: pldm_msgbuf_extract_array_char)(ctx, dst, count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930779
Andrew Jeffery76712f62024-05-22 15:19:00 +0930780__attribute__((always_inline)) static inline int
781pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700782{
783 uint32_t val = htole32(src);
784
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930785 assert(ctx);
786
787 if (!ctx->cursor) {
788 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700789 }
790
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930791 static_assert(
792 // NOLINTNEXTLINE(bugprone-sizeof-expression)
793 sizeof(src) < INTMAX_MAX,
794 "The following addition may not uphold the runtime assertion");
795 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
796 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930797 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930798 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700799 ctx->remaining -= sizeof(src);
800 assert(ctx->remaining >= 0);
801 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930802 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700803 }
804
805 memcpy(ctx->cursor, &val, sizeof(val));
806 ctx->cursor += sizeof(src);
807
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930808 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700809}
810
Andrew Jeffery76712f62024-05-22 15:19:00 +0930811__attribute__((always_inline)) static inline int
812pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700813{
814 uint16_t val = htole16(src);
815
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930816 assert(ctx);
817
818 if (!ctx->cursor) {
819 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700820 }
821
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930822 static_assert(
823 // NOLINTNEXTLINE(bugprone-sizeof-expression)
824 sizeof(src) < INTMAX_MAX,
825 "The following addition may not uphold the runtime assertion");
826 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
827 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930828 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930829 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700830 ctx->remaining -= sizeof(src);
831 assert(ctx->remaining >= 0);
832 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930833 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700834 }
835
836 memcpy(ctx->cursor, &val, sizeof(val));
837 ctx->cursor += sizeof(src);
838
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930839 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700840}
841
Andrew Jeffery76712f62024-05-22 15:19:00 +0930842__attribute__((always_inline)) static inline int
843pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700844{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930845 assert(ctx);
846
847 if (!ctx->cursor) {
848 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700849 }
850
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930851 static_assert(
852 // NOLINTNEXTLINE(bugprone-sizeof-expression)
853 sizeof(src) < INTMAX_MAX,
854 "The following addition may not uphold the runtime assertion");
855 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
856 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930857 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930858 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700859 ctx->remaining -= sizeof(src);
860 assert(ctx->remaining >= 0);
861 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930862 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700863 }
864
865 memcpy(ctx->cursor, &src, sizeof(src));
866 ctx->cursor += sizeof(src);
867
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930868 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700869}
870
Andrew Jeffery76712f62024-05-22 15:19:00 +0930871__attribute__((always_inline)) static inline int
872pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700873{
874 int32_t val = htole32(src);
875
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930876 assert(ctx);
877
878 if (!ctx->cursor) {
879 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700880 }
881
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930882 static_assert(
883 // NOLINTNEXTLINE(bugprone-sizeof-expression)
884 sizeof(src) < INTMAX_MAX,
885 "The following addition may not uphold the runtime assertion");
886 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
887 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930888 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930889 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700890 ctx->remaining -= sizeof(src);
891 assert(ctx->remaining >= 0);
892 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930893 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700894 }
895
896 memcpy(ctx->cursor, &val, sizeof(val));
897 ctx->cursor += sizeof(src);
898
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930899 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700900}
901
Andrew Jeffery76712f62024-05-22 15:19:00 +0930902__attribute__((always_inline)) static inline int
903pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700904{
905 int16_t val = htole16(src);
906
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930907 assert(ctx);
908
909 if (!ctx->cursor) {
910 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700911 }
912
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930913 static_assert(
914 // NOLINTNEXTLINE(bugprone-sizeof-expression)
915 sizeof(src) < INTMAX_MAX,
916 "The following addition may not uphold the runtime assertion");
917 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
918 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930919 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930920 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700921 ctx->remaining -= sizeof(src);
922 assert(ctx->remaining >= 0);
923 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930924 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700925 }
926
927 memcpy(ctx->cursor, &val, sizeof(val));
928 ctx->cursor += sizeof(src);
929
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930930 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700931}
932
Andrew Jeffery76712f62024-05-22 15:19:00 +0930933__attribute__((always_inline)) static inline int
934pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700935{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930936 assert(ctx);
937
938 if (!ctx->cursor) {
939 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700940 }
941
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930942 static_assert(
943 // NOLINTNEXTLINE(bugprone-sizeof-expression)
944 sizeof(src) < INTMAX_MAX,
945 "The following addition may not uphold the runtime assertion");
946 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
947 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930948 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930949 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700950 ctx->remaining -= sizeof(src);
951 assert(ctx->remaining >= 0);
952 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930953 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700954 }
955
956 memcpy(ctx->cursor, &src, sizeof(src));
957 ctx->cursor += sizeof(src);
958
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930959 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700960}
961
962#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930963 _Generic((src), \
964 uint8_t: pldm_msgbuf_insert_uint8, \
965 int8_t: pldm_msgbuf_insert_int8, \
966 uint16_t: pldm_msgbuf_insert_uint16, \
967 int16_t: pldm_msgbuf_insert_int16, \
968 uint32_t: pldm_msgbuf_insert_uint32, \
969 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700970
Andrew Jeffery76712f62024-05-22 15:19:00 +0930971__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930972// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
973pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, const void *src,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930974 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700975{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930976 assert(ctx);
977
978 if (!ctx->cursor || !src) {
979 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700980 }
981
982 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930983 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700984 }
985
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930986#if INTMAX_MAX < SIZE_MAX
987 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930988 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700989 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930990#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700991
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930992 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930993 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930994 }
995 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700996 assert(ctx->remaining >= 0);
997 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930998 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700999 }
1000
Andrew Jefferya065ecc2023-10-27 15:02:11 +10301001 memcpy(ctx->cursor, src, count);
1002 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001003
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301004 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001005}
1006
Andrew Jeffery1c571442024-07-08 10:25:48 +09301007__attribute__((always_inline)) static inline int
1008pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, const char *src,
1009 size_t count)
1010{
1011 return pldm__msgbuf_insert_array_void(ctx, src, count);
1012}
1013
1014__attribute__((always_inline)) static inline int
1015pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
1016 size_t count)
1017{
1018 return pldm__msgbuf_insert_array_void(ctx, src, count);
1019}
1020
Thu Nguyen062c8762023-04-22 20:45:04 +07001021#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +09301022 _Generic((*(src)), \
1023 uint8_t: pldm_msgbuf_insert_array_uint8, \
1024 char: pldm_msgbuf_insert_array_char)(dst, src, count)
Thu Nguyen062c8762023-04-22 20:45:04 +07001025
Andrew Jeffery76712f62024-05-22 15:19:00 +09301026__attribute__((always_inline)) static inline int
1027pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
1028 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +07001029{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301030 assert(ctx);
1031
1032 if (!ctx->cursor || !cursor || *cursor) {
1033 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001034 }
1035
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301036#if INTMAX_MAX < SIZE_MAX
1037 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301038 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001039 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301040#endif
Thu Nguyen062c8762023-04-22 20:45:04 +07001041
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301042 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301043 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301044 }
1045 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +07001046 assert(ctx->remaining >= 0);
1047 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301048 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001049 }
1050
1051 *cursor = ctx->cursor;
1052 ctx->cursor += required;
1053
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301054 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001055}
1056
Andrew Jeffery76712f62024-05-22 15:19:00 +09301057__attribute__((always_inline)) static inline int
Thu Nguyen9c83d682024-07-02 08:43:09 +00001058pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
1059 size_t *length)
1060{
1061 intmax_t measured;
1062
1063 assert(ctx);
1064
1065 if (!ctx->cursor || (cursor && *cursor)) {
1066 return pldm_msgbuf_status(ctx, EINVAL);
1067 }
1068
1069 if (ctx->remaining < 0) {
1070 /* Tracking the amount of overflow gets disturbed here */
1071 return pldm_msgbuf_status(ctx, EOVERFLOW);
1072 }
1073
1074 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1075 if (measured == ctx->remaining) {
1076 /*
1077 * We have hit the end of the buffer prior to the NUL terminator.
1078 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
1079 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1080 * return an error.
1081 */
1082 ctx->remaining = -1;
1083 return pldm_msgbuf_status(ctx, EOVERFLOW);
1084 }
1085
1086 /* Include the NUL terminator in the span length, as spans are opaque */
1087 measured++;
1088
1089 if (ctx->remaining < INTMAX_MIN + measured) {
1090 return pldm_msgbuf_status(ctx, EOVERFLOW);
1091 }
1092
1093 ctx->remaining -= measured;
1094 assert(ctx->remaining >= 0);
1095 if (ctx->remaining < 0) {
1096 return pldm_msgbuf_status(ctx, EOVERFLOW);
1097 }
1098
1099 if (cursor) {
1100 *cursor = ctx->cursor;
1101 }
1102
1103 ctx->cursor += measured;
1104
1105 if (length) {
1106 *length = measured;
1107 }
1108
1109 return 0;
1110}
1111
1112__attribute__((always_inline)) static inline int
Thu Nguyen15237782024-07-02 09:30:41 +00001113pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1114 size_t *length)
1115{
1116 static const char16_t term = 0;
1117 ptrdiff_t measured;
1118 void *end;
1119
1120 assert(ctx);
1121
1122 if (!ctx->cursor || (cursor && *cursor)) {
1123 return pldm_msgbuf_status(ctx, EINVAL);
1124 }
1125
1126 if (ctx->remaining < 0) {
1127 /* Tracking the amount of overflow gets disturbed here */
1128 return pldm_msgbuf_status(ctx, EOVERFLOW);
1129 }
1130
1131 /*
1132 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1133 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1134 * start of the string
1135 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301136 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001137 do {
1138 if (end != ctx->cursor) {
1139 /*
1140 * If we've looped we've found a relatively-unaligned NUL code-point.
1141 * Scan again from a relatively-aligned start point.
1142 */
1143 end = (char *)end + 1;
1144 }
1145 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301146 end = memmem(end, ctx->remaining - measured, &term,
1147 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001148 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1149
1150 if (!end) {
1151 /*
1152 * Optimistically, the last required pattern byte was one beyond the end of
1153 * the buffer. Setting ctx->remaining negative ensures the
1154 * `pldm_msgbuf_destroy*()` APIs also return an error.
1155 */
1156 ctx->remaining = -1;
1157 return pldm_msgbuf_status(ctx, EOVERFLOW);
1158 }
1159
1160 end = (char *)end + sizeof(char16_t);
1161 measured = (char *)end - (char *)ctx->cursor;
1162
1163#if INTMAX_MAX < PTRDIFF_MAX
1164 if (measured >= INTMAX_MAX) {
1165 return pldm_msgbuf_status(ctx, EOVERFLOW);
1166 }
1167#endif
1168
1169 if (ctx->remaining < INTMAX_MIN + (intmax_t)measured) {
1170 assert(ctx->remaining < 0);
1171 return pldm_msgbuf_status(ctx, EOVERFLOW);
1172 }
1173
1174 ctx->remaining -= (intmax_t)measured;
1175 assert(ctx->remaining >= 0);
1176 if (ctx->remaining < 0) {
1177 return pldm_msgbuf_status(ctx, EOVERFLOW);
1178 }
1179
1180 if (cursor) {
1181 *cursor = ctx->cursor;
1182 }
1183
1184 ctx->cursor += measured;
1185
1186 if (length) {
1187 *length = (size_t)measured;
1188 }
1189
1190 return 0;
1191}
1192
1193__attribute__((always_inline)) static inline int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301194pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001195{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301196 assert(ctx);
1197
1198 if (!ctx->cursor || !cursor || *cursor || !len) {
1199 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001200 }
1201
1202 assert(ctx->remaining >= 0);
1203 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301204 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001205 }
1206
1207 *cursor = ctx->cursor;
1208 ctx->cursor += ctx->remaining;
1209 *len = ctx->remaining;
1210 ctx->remaining = 0;
1211
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301212 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001213}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001214
1215/**
1216 * @brief pldm_msgbuf copy data between two msg buffers
1217 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301218 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1219 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001220 * @param[in] size - size of data to be copied
1221 * @param[in] description - description of data copied
1222 *
1223 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1224 * PLDM_ERROR_INVALID_LENGTH otherwise.
1225 * PLDM_ERROR_INVALID_DATA if input is invalid
1226 */
1227#define pldm_msgbuf_copy(dst, src, type, name) \
1228 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301229__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001230// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301231pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
1232 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001233{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301234 assert(src);
1235 assert(dst);
1236 assert(src->mode == dst->mode);
1237
1238 if (!src->cursor || !dst->cursor || !description) {
1239 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001240 }
1241
1242#if INTMAX_MAX < SIZE_MAX
1243 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301244 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001245 }
1246#endif
1247
1248 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301249 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001250 }
1251
1252 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301253 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001254 }
1255
1256 src->remaining -= (intmax_t)size;
1257 assert(src->remaining >= 0);
1258 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301259 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001260 }
1261
1262 dst->remaining -= (intmax_t)size;
1263 assert(dst->remaining >= 0);
1264 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301265 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001266 }
1267
1268 memcpy(dst->cursor, src->cursor, size);
1269 src->cursor += size;
1270 dst->cursor += size;
1271
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301272 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001273}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301274
Andrew Jeffery8b879602024-07-08 12:50:19 +09301275__attribute__((always_inline)) static inline int
1276pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1277{
1278 void *ascii = NULL;
1279 size_t len = 0;
1280 int rc;
1281
1282 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1283 if (rc < 0) {
1284 return rc;
1285 }
1286
1287 return pldm__msgbuf_insert_array_void(dst, ascii, len);
1288}
1289
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301290__attribute__((always_inline)) static inline int
1291pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1292{
1293 void *utf16 = NULL;
1294 size_t len = 0;
1295 int rc;
1296
1297 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1298 if (rc < 0) {
1299 return rc;
1300 }
1301
1302 return pldm__msgbuf_insert_array_void(dst, utf16, len);
1303}
1304
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301305#ifdef __cplusplus
1306}
1307#endif
1308
Andrew Jeffery66c77232024-04-24 11:42:02 +09301309#ifdef __cplusplus
1310#include <type_traits>
1311
1312template <typename T>
1313static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1314 void *buf)
1315{
1316 static_assert(std::is_same<uint8_t *, T>::value);
1317 return pldm__msgbuf_extract_uint8(ctx, buf);
1318}
1319
1320template <typename T>
1321static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1322 void *buf)
1323{
1324 static_assert(std::is_same<int8_t *, T>::value);
1325 return pldm__msgbuf_extract_int8(ctx, buf);
1326}
1327
1328template <typename T>
1329static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1330 void *buf)
1331{
1332 static_assert(std::is_same<uint16_t *, T>::value);
1333 return pldm__msgbuf_extract_uint16(ctx, buf);
1334}
1335
1336template <typename T>
1337static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1338 void *buf)
1339{
1340 static_assert(std::is_same<int16_t *, T>::value);
1341 return pldm__msgbuf_extract_int16(ctx, buf);
1342}
1343
1344template <typename T>
1345static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1346 void *buf)
1347{
1348 static_assert(std::is_same<uint32_t *, T>::value);
1349 return pldm__msgbuf_extract_uint32(ctx, buf);
1350}
1351
1352template <typename T>
1353static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1354 void *buf)
1355{
1356 static_assert(std::is_same<int32_t *, T>::value);
1357 return pldm__msgbuf_extract_int32(ctx, buf);
1358}
1359
1360template <typename T>
1361static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1362 void *buf)
1363{
1364 static_assert(std::is_same<real32_t *, T>::value);
1365 return pldm__msgbuf_extract_real32(ctx, buf);
1366}
1367#endif
1368
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301369#endif /* BUF_H */