blob: 1d06a75d19e787252730f3861c1fd9483b96d4c4 [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
Thu Nguyen15237782024-07-02 09:30:41 +00005// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
6#ifndef _GNU_SOURCE
7/* For memmem(3) */
8#define _GNU_SOURCE
9#endif
10// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
11
Andrew Jeffery66c77232024-04-24 11:42:02 +093012/*
13 * Historically, many of the structs exposed in libpldm's public headers are
14 * defined with __attribute__((packed)). This is unfortunate: it gives the
15 * impression that a wire-format buffer can be cast to the message type to make
16 * the message's fields easily accessible. As it turns out, that's not
17 * that's valid for several reasons:
18 *
19 * 1. Casting the wire-format buffer to a struct of the message type doesn't
20 * abstract the endianness of message field values
21 *
22 * 2. Some messages contain packed tagged union fields which cannot be properly
23 * described in a C struct.
24 *
25 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
26 * that is type-safe, spatially memory-safe, endian-safe, performant, and
27 * free of undefined-behaviour. Message structs that are added to the public
28 * library API should no-longer be marked __attribute__((packed)), and the
29 * implementation of their encode and decode functions must exploit the msgbuf
30 * API.
31 *
32 * However, we would like to allow implementation of codec functions in terms of
33 * msgbuf APIs even if they're decoding a message into a (historically) packed
34 * struct. Some of the complexity that follows is a consequence of the packed/
35 * unpacked conflict.
36 */
37
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103038#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093039/*
40 * Fix up C11's _Static_assert() vs C++'s static_assert().
41 *
42 * Can we please have nice things for once.
43 */
44// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
45#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103046extern "C" {
47#endif
48
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103049#include <libpldm/base.h>
50#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103051
Andrew Jeffery66c77232024-04-24 11:42:02 +093052#include "compiler.h"
53
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103054#include <assert.h>
55#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093056#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103057#include <limits.h>
58#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093059#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103060#include <string.h>
61#include <sys/types.h>
Thu Nguyen15237782024-07-02 09:30:41 +000062#include <uchar.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103063
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093064/*
65 * We can't use static_assert() outside of some other C construct. Deal
66 * with high-level global assertions by burying them in an unused struct
67 * declaration, that has a sole member for compliance with the requirement that
68 * types must have a size.
69*/
70static struct {
71 static_assert(
72 INTMAX_MAX != SIZE_MAX,
73 "Extraction and insertion value comparisons may be broken");
74 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
75 "Extraction and insertion arithmetic may be broken");
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093076 static_assert(PLDM_SUCCESS == 0, "Error handling is broken");
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093077 int compliance;
78} build_assertions __attribute__((unused));
79
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093080enum pldm_msgbuf_error_mode {
81 PLDM_MSGBUF_PLDM_CC = 0x5a,
82 PLDM_MSGBUF_C_ERRNO = 0xa5,
83};
84
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103085struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070086 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093087 intmax_t remaining;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093088 enum pldm_msgbuf_error_mode mode;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103089};
90
Andrew Jefferyd861a682024-06-03 21:43:09 +093091/**
92 * @brief Either negate an errno value or return a value mapped to a PLDM
93 * completion code.
94 *
95 * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API
96 * for ergonomics. It's preferred that we don't try to unify this with
97 * `pldm_xlate_errno()` from src/api.h despite the similarities.
98 *
99 * @param[in] ctx - The msgbuf context providing the personality info
100 * @param[in] err - The positive errno value to translate
101 *
102 * @return Either the negated value of @p err if the context's error mode is
103 * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the
104 * error mode is `PLDM_MSGBUF_PLDM_CC`.
105 */
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930106__attribute__((always_inline)) static inline int
107pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err)
108{
109 int rc;
110
111 assert(err != 0);
112 assert(err <= INT_MAX);
113
114 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
115 if (err > INT_MAX) {
116 return -EINVAL;
117 }
118
119 static_assert(INT_MIN + INT_MAX < 0,
120 "Arithmetic assumption failure");
121 return -((int)err);
122 }
123
124 if (err > INT_MAX) {
125 return PLDM_ERROR;
126 }
127
128 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
129 switch (err) {
130 case EINVAL:
131 rc = PLDM_ERROR_INVALID_DATA;
132 break;
133 case EBADMSG:
134 case EOVERFLOW:
135 rc = PLDM_ERROR_INVALID_LENGTH;
136 break;
137 default:
138 assert(false);
139 rc = PLDM_ERROR;
140 break;
141 }
142
143 assert(rc > 0);
144 return rc;
145}
146
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030147/**
148 * @brief Initialize pldm buf struct for buf extractor
149 *
150 * @param[out] ctx - pldm_msgbuf context for extractor
151 * @param[in] minsize - The minimum required length of buffer `buf`
152 * @param[in] buf - buffer to be extracted
153 * @param[in] len - size of buffer
154 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930155 * @return 0 on success, otherwise an error code appropriate for the current
156 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030157 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930158__attribute__((always_inline)) static inline int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930159// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
160pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
161 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030162{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930163 assert(ctx);
164 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
165 ctx->mode == PLDM_MSGBUF_C_ERRNO);
166
167 if (!buf) {
168 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030169 }
170
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930171 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930172 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030173 }
174
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930175#if INTMAX_MAX < SIZE_MAX
176 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930177 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930178 }
179#endif
180
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930181 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930182 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030183 }
184
185 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930186 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030187
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930188 return 0;
189}
190
191/**
192 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
193 *
194 * @see pldm__msgbuf_init
195 *
196 * @param[out] ctx - pldm_msgbuf context for extractor
197 * @param[in] minsize - The minimum required length of buffer `buf`
198 * @param[in] buf - buffer to be extracted
199 * @param[in] len - size of buffer
200 *
201 * @return PLDM_SUCCESS if the provided buffer region is sensible,
202 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
203 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
204 */
205__attribute__((always_inline)) static inline int
206pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
207 size_t len)
208{
209 if (!ctx) {
210 return PLDM_ERROR_INVALID_DATA;
211 }
212
213 ctx->mode = PLDM_MSGBUF_PLDM_CC;
214 return pldm__msgbuf_init(ctx, minsize, buf, len);
215}
216
217/**
218 * @brief Initialise a msgbuf instance to return errors as negative errno values
219 *
220 * @see pldm__msgbuf_init
221 *
222 * @param[out] ctx - pldm_msgbuf context for extractor
223 * @param[in] minsize - The minimum required length of buffer `buf`
224 * @param[in] buf - buffer to be extracted
225 * @param[in] len - size of buffer
226 *
227 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
228 * pointer parameters are invalid, or -EOVERFLOW if length constraints
229 * are violated.
230 */
231__attribute__((always_inline)) static inline int
232pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
233 size_t len)
234{
235 if (!ctx) {
236 return -EINVAL;
237 }
238
239 ctx->mode = PLDM_MSGBUF_C_ERRNO;
240 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030241}
242
243/**
244 * @brief Validate buffer overflow state
245 *
246 * @param[in] ctx - pldm_msgbuf context for extractor
247 *
248 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
249 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
250 * prior accesses would have occurred beyond the bounds of the buffer, and
251 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
252 * pointer.
253 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930254__attribute__((always_inline)) static inline int
255pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030256{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930257 assert(ctx);
258 if (ctx->remaining < 0) {
259 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030260 }
261
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930262 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030263}
264
265/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930266 * @brief Test whether a message buffer has been exactly consumed
267 *
268 * @param[in] ctx - pldm_msgbuf context for extractor
269 *
270 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
271 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
272 * indicates that an incorrect sequence of accesses have occurred, and
273 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
274 * pointer.
275 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930276__attribute__((always_inline)) static inline int
277pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930278{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930279 assert(ctx);
280 if (ctx->remaining != 0) {
281 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930282 }
283
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930284 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930285}
286
287/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030288 * @brief Destroy the pldm buf
289 *
290 * @param[in] ctx - pldm_msgbuf context for extractor
291 *
292 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
293 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
294 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
295 * bounds of the buffer.
296 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930297__attribute__((always_inline)) static inline int
298pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030299{
300 int valid;
301
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930302 assert(ctx);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030303 valid = pldm_msgbuf_validate(ctx);
304
305 ctx->cursor = NULL;
306 ctx->remaining = 0;
307
308 return valid;
309}
310
311/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930312 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
313 * has been completely consumed without overflow
314 *
315 * @param[in] ctx - pldm_msgbuf context
316 *
317 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
318 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
319 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
320 * have occurred byond the bounds of the buffer
321 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930322__attribute__((always_inline)) static inline int
323pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930324{
325 int consumed;
326
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930327 assert(ctx);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930328 consumed = pldm_msgbuf_consumed(ctx);
329
330 ctx->cursor = NULL;
331 ctx->remaining = 0;
332
333 return consumed;
334}
335
Andrew Jeffery66c77232024-04-24 11:42:02 +0930336/*
337 * Exploit the pre-processor to perform type checking by macro substitution.
338 *
339 * A C type is defined by its alignment as well as its object
340 * size, and compilers have a hammer to enforce it in the form of
341 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
342 * the libpldm public API this presents a problem: Naively attempting to use the
343 * msgbuf APIs on a member of a packed struct would yield an error.
344 *
345 * The msgbuf APIs are implemented such that data is moved through unaligned
346 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
347 * make the object pointers take a trip through `void *` at its API boundary.
348 * That presents a bit too much of an opportunity to non-surgically remove your
349 * own foot, so here we set about doing something to mitigate that as well.
350 *
351 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
352 * only for the purpose of object sizes, disregarding alignment. We have a few
353 * constraints that cause some headaches:
354 *
355 * 1. We have to perform the type-check before a call through a C function,
356 * as the function must take the object pointer argument as `void *`.
357 * Essentially, this constrains us to doing something with macros.
358 *
359 * 2. While libpldm is a C library, its test suite is written in C++ to take
360 * advantage of gtest.
361 *
362 * 3. Ideally we'd do something with C's `static_assert()`, however
363 * `static_assert()` is defined as void, and as we're constrained to macros,
364 * using `static_assert()` would require a statement-expression
365 *
366 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
367 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
368 * the purpose of enabling statement-expressions in this one instance.
369 *
370 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
371 * however it's implemented in terms of `_Generic()`, which is not available
372 * in C++.
373 *
374 * Combined this means we need separate solutions for C and C++.
375 *
376 * For C, as we don't have statement-expressions, we need to exploit some other
377 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
378 * API function call. We also have to take care of the fact that the call-sites
379 * may be in the context of a variable assignment for error-handling purposes.
380 * The key observation is that we can use the comma operator as a sequence point
381 * to order the type check before the API call, discarding the "result" value of
382 * the type check and yielding the return value of the API call.
383 *
384 * C++ could be less of a headache than the C as we can leverage template
385 * functions. An advantage of template functions is that while their definition
386 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530387 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930388 * we have in the C path. However, the use of the msgbuf APIs in the test suite
389 * still makes things somewhat tricky, as the call-sites in the test suite are
390 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
391 * takes both the object type and the required type as template arguments, and
392 * then define the object pointer parameter as `void *` for a call through to
393 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
394 * encapsulated in gtest macros, use of commas in the template specification
395 * causes pre-processor confusion. In this way we're constrained to only one
396 * template argument per function.
397 *
398 * Implement the C++ path using template functions that take the destination
399 * object type as a template argument, while the name of the function symbols
400 * are derived from the required type. The manual implementations of these
401 * appear at the end of the header. The type safety is actually enforced
402 * by `static_assert()` this time, as we can use statements as we're not
403 * constrained to an expression in the templated function body.
404 *
405 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
406 * double-evaluation of some arguments. We're not yet bothered by this for two
407 * reasons:
408 *
409 * 1. The nature of the current call-sites are such that there are no
410 * argument expressions that result in undesirable side-effects
411 *
412 * 2. It's an API internal to the libpldm implementation, and we can fix things
413 * whenever something crops up the violates the observation in 1.
414 */
415#ifdef __cplusplus
416#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
417 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
418#else
419#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
420 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
421#endif
422
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930423/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030424 * @brief pldm_msgbuf extractor for a uint8_t
425 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530426 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030427 * @param[out] dst - destination of extracted value
428 *
429 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
430 * PLDM_ERROR_INVALID_LENGTH otherwise.
431 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
432 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930433#define pldm_msgbuf_extract_uint8(ctx, dst) \
434 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
435 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930436__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930437// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930438pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030439{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930440 assert(ctx);
441
442 if (!ctx->cursor || !dst) {
443 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030444 }
445
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930446 if (ctx->remaining == INTMAX_MIN) {
447 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930448 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930449 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930450 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030451 assert(ctx->remaining >= 0);
452 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930453 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030454 }
455
Andrew Jeffery66c77232024-04-24 11:42:02 +0930456 memcpy(dst, ctx->cursor, sizeof(uint8_t));
457
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030458 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930459 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030460}
461
Andrew Jeffery66c77232024-04-24 11:42:02 +0930462#define pldm_msgbuf_extract_int8(ctx, dst) \
463 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
464 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930465__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930466// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930467pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030468{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930469 assert(ctx);
470
471 if (!ctx->cursor || !dst) {
472 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030473 }
474
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930475 if (ctx->remaining == INTMAX_MIN) {
476 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930477 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930478 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930479 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030480 assert(ctx->remaining >= 0);
481 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930482 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030483 }
484
Andrew Jeffery66c77232024-04-24 11:42:02 +0930485 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030486 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930487 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030488}
489
Andrew Jeffery66c77232024-04-24 11:42:02 +0930490#define pldm_msgbuf_extract_uint16(ctx, dst) \
491 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
492 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930493__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930494// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930495pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030496{
497 uint16_t ldst;
498
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930499 assert(ctx);
500
501 if (!ctx->cursor || !dst) {
502 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030503 }
504
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930505 // Check for underflow while tracking the magnitude of the buffer overflow
506 static_assert(
507 // NOLINTNEXTLINE(bugprone-sizeof-expression)
508 sizeof(ldst) < INTMAX_MAX,
509 "The following addition may not uphold the runtime assertion");
510 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
511 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930512 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930513 }
514
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030515 // Check for buffer overflow. If we overflow, account for the request as
516 // negative values in ctx->remaining. This way we can debug how far
517 // we've overflowed.
518 ctx->remaining -= sizeof(ldst);
519
520 // Prevent the access if it would overflow. First, assert so we blow up
521 // the test suite right at the point of failure. However, cater to
522 // -DNDEBUG by explicitly testing that the access is valid.
523 assert(ctx->remaining >= 0);
524 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930525 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030526 }
527
528 // Use memcpy() to have the compiler deal with any alignment
529 // issues on the target architecture
530 memcpy(&ldst, ctx->cursor, sizeof(ldst));
531
532 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930533 ldst = le16toh(ldst);
534
535 // Allow storing to unaligned
536 memcpy(dst, &ldst, sizeof(ldst));
537
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030538 ctx->cursor += sizeof(ldst);
539
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930540 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030541}
542
Andrew Jeffery66c77232024-04-24 11:42:02 +0930543#define pldm_msgbuf_extract_int16(ctx, dst) \
544 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
545 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930546__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930547// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930548pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030549{
550 int16_t ldst;
551
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930552 assert(ctx);
553
554 if (!ctx->cursor || !dst) {
555 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030556 }
557
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930558 static_assert(
559 // NOLINTNEXTLINE(bugprone-sizeof-expression)
560 sizeof(ldst) < INTMAX_MAX,
561 "The following addition may not uphold the runtime assertion");
562 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
563 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930564 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930565 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030566 ctx->remaining -= sizeof(ldst);
567 assert(ctx->remaining >= 0);
568 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930569 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030570 }
571
572 memcpy(&ldst, ctx->cursor, sizeof(ldst));
573
Andrew Jeffery66c77232024-04-24 11:42:02 +0930574 ldst = le16toh(ldst);
575 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030576 ctx->cursor += sizeof(ldst);
577
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930578 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030579}
580
Andrew Jeffery66c77232024-04-24 11:42:02 +0930581#define pldm_msgbuf_extract_uint32(ctx, dst) \
582 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
583 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930584__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930585// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930586pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030587{
588 uint32_t ldst;
589
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930590 assert(ctx);
591
592 if (!ctx->cursor || !dst) {
593 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030594 }
595
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930596 static_assert(
597 // NOLINTNEXTLINE(bugprone-sizeof-expression)
598 sizeof(ldst) < INTMAX_MAX,
599 "The following addition may not uphold the runtime assertion");
600 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
601 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930602 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930603 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030604 ctx->remaining -= sizeof(ldst);
605 assert(ctx->remaining >= 0);
606 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930607 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030608 }
609
610 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930611 ldst = le32toh(ldst);
612 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030613 ctx->cursor += sizeof(ldst);
614
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930615 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030616}
617
Andrew Jeffery66c77232024-04-24 11:42:02 +0930618#define pldm_msgbuf_extract_int32(ctx, dst) \
619 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
620 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930621__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930622// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930623pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030624{
625 int32_t ldst;
626
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930627 assert(ctx);
628
629 if (!ctx->cursor || !dst) {
630 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030631 }
632
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930633 static_assert(
634 // NOLINTNEXTLINE(bugprone-sizeof-expression)
635 sizeof(ldst) < INTMAX_MAX,
636 "The following addition may not uphold the runtime assertion");
637 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
638 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930639 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930640 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030641 ctx->remaining -= sizeof(ldst);
642 assert(ctx->remaining >= 0);
643 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930644 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030645 }
646
647 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930648 ldst = le32toh(ldst);
649 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030650 ctx->cursor += sizeof(ldst);
651
652 return PLDM_SUCCESS;
653}
654
Andrew Jeffery66c77232024-04-24 11:42:02 +0930655#define pldm_msgbuf_extract_real32(ctx, dst) \
656 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
657 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930658__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930659// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930660pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030661{
662 uint32_t ldst;
663
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930664 static_assert(sizeof(real32_t) == sizeof(ldst),
665 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930666
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930667 assert(ctx);
668
669 if (!ctx->cursor || !dst) {
670 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030671 }
672
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930673 static_assert(
674 // NOLINTNEXTLINE(bugprone-sizeof-expression)
675 sizeof(ldst) < INTMAX_MAX,
676 "The following addition may not uphold the runtime assertion");
677 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
678 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930679 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930680 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030681 ctx->remaining -= sizeof(ldst);
682 assert(ctx->remaining >= 0);
683 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930684 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030685 }
686
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030687 memcpy(&ldst, ctx->cursor, sizeof(ldst));
688 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930689 memcpy(dst, &ldst, sizeof(ldst));
690 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030691
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930692 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030693}
694
Andrew Jeffery66c77232024-04-24 11:42:02 +0930695/**
696 * Extract the field at the msgbuf cursor into the lvalue named by dst.
697 *
698 * @param ctx The msgbuf context object
699 * @param dst The lvalue into which the field at the msgbuf cursor should be
700 * extracted
701 *
702 * @return PLDM_SUCCESS on success, otherwise another value on error
703 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030704#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930705 _Generic((dst), \
706 uint8_t: pldm__msgbuf_extract_uint8, \
707 int8_t: pldm__msgbuf_extract_int8, \
708 uint16_t: pldm__msgbuf_extract_uint16, \
709 int16_t: pldm__msgbuf_extract_int16, \
710 uint32_t: pldm__msgbuf_extract_uint32, \
711 int32_t: pldm__msgbuf_extract_int32, \
712 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
713
714/**
715 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
716 *
717 * @param ctx The msgbuf context object
718 * @param dst The pointer to the object into which the field at the msgbuf
719 * cursor should be extracted
720 *
721 * @return PLDM_SUCCESS on success, otherwise another value on error
722 */
723#define pldm_msgbuf_extract_p(ctx, dst) \
724 _Generic((dst), \
725 uint8_t *: pldm__msgbuf_extract_uint8, \
726 int8_t *: pldm__msgbuf_extract_int8, \
727 uint16_t *: pldm__msgbuf_extract_uint16, \
728 int16_t *: pldm__msgbuf_extract_int16, \
729 uint32_t *: pldm__msgbuf_extract_uint32, \
730 int32_t *: pldm__msgbuf_extract_int32, \
731 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030732
Andrew Jeffery76712f62024-05-22 15:19:00 +0930733__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930734// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
735pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, void *dst,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930736 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930737{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930738 assert(ctx);
739
740 if (!ctx->cursor || !dst) {
741 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930742 }
743
744 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930745 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930746 }
747
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930748#if INTMAX_MAX < SIZE_MAX
749 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930750 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930751 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930752#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930753
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930754 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930755 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930756 }
757 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930758 assert(ctx->remaining >= 0);
759 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930760 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930761 }
762
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030763 memcpy(dst, ctx->cursor, count);
764 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930765
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930766 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930767}
768
Andrew Jeffery1c571442024-07-08 10:25:48 +0930769__attribute__((always_inline)) static inline int
770pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, char *dst, size_t count)
771{
772 return pldm__msgbuf_extract_array_void(ctx, dst, count);
773}
774
775__attribute__((always_inline)) static inline int
776pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
777 size_t count)
778{
779 return pldm__msgbuf_extract_array_void(ctx, dst, count);
780}
781
Andrew Jeffery369b1212023-04-20 15:44:48 +0930782#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930783 _Generic((*(dst)), \
784 uint8_t: pldm_msgbuf_extract_array_uint8, \
785 char: pldm_msgbuf_extract_array_char)(ctx, dst, count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930786
Andrew Jeffery76712f62024-05-22 15:19:00 +0930787__attribute__((always_inline)) static inline int
788pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700789{
790 uint32_t val = htole32(src);
791
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930792 assert(ctx);
793
794 if (!ctx->cursor) {
795 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700796 }
797
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930798 static_assert(
799 // NOLINTNEXTLINE(bugprone-sizeof-expression)
800 sizeof(src) < INTMAX_MAX,
801 "The following addition may not uphold the runtime assertion");
802 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
803 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930804 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930805 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700806 ctx->remaining -= sizeof(src);
807 assert(ctx->remaining >= 0);
808 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930809 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700810 }
811
812 memcpy(ctx->cursor, &val, sizeof(val));
813 ctx->cursor += sizeof(src);
814
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930815 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700816}
817
Andrew Jeffery76712f62024-05-22 15:19:00 +0930818__attribute__((always_inline)) static inline int
819pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700820{
821 uint16_t val = htole16(src);
822
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930823 assert(ctx);
824
825 if (!ctx->cursor) {
826 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700827 }
828
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930829 static_assert(
830 // NOLINTNEXTLINE(bugprone-sizeof-expression)
831 sizeof(src) < INTMAX_MAX,
832 "The following addition may not uphold the runtime assertion");
833 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
834 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930835 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930836 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700837 ctx->remaining -= sizeof(src);
838 assert(ctx->remaining >= 0);
839 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930840 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700841 }
842
843 memcpy(ctx->cursor, &val, sizeof(val));
844 ctx->cursor += sizeof(src);
845
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930846 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700847}
848
Andrew Jeffery76712f62024-05-22 15:19:00 +0930849__attribute__((always_inline)) static inline int
850pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700851{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930852 assert(ctx);
853
854 if (!ctx->cursor) {
855 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700856 }
857
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930858 static_assert(
859 // NOLINTNEXTLINE(bugprone-sizeof-expression)
860 sizeof(src) < INTMAX_MAX,
861 "The following addition may not uphold the runtime assertion");
862 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
863 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930864 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930865 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700866 ctx->remaining -= sizeof(src);
867 assert(ctx->remaining >= 0);
868 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930869 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700870 }
871
872 memcpy(ctx->cursor, &src, sizeof(src));
873 ctx->cursor += sizeof(src);
874
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930875 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700876}
877
Andrew Jeffery76712f62024-05-22 15:19:00 +0930878__attribute__((always_inline)) static inline int
879pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700880{
881 int32_t val = htole32(src);
882
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930883 assert(ctx);
884
885 if (!ctx->cursor) {
886 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700887 }
888
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930889 static_assert(
890 // NOLINTNEXTLINE(bugprone-sizeof-expression)
891 sizeof(src) < INTMAX_MAX,
892 "The following addition may not uphold the runtime assertion");
893 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
894 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930895 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930896 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700897 ctx->remaining -= sizeof(src);
898 assert(ctx->remaining >= 0);
899 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930900 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700901 }
902
903 memcpy(ctx->cursor, &val, sizeof(val));
904 ctx->cursor += sizeof(src);
905
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930906 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700907}
908
Andrew Jeffery76712f62024-05-22 15:19:00 +0930909__attribute__((always_inline)) static inline int
910pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700911{
912 int16_t val = htole16(src);
913
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930914 assert(ctx);
915
916 if (!ctx->cursor) {
917 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700918 }
919
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930920 static_assert(
921 // NOLINTNEXTLINE(bugprone-sizeof-expression)
922 sizeof(src) < INTMAX_MAX,
923 "The following addition may not uphold the runtime assertion");
924 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
925 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930926 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930927 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700928 ctx->remaining -= sizeof(src);
929 assert(ctx->remaining >= 0);
930 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930931 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700932 }
933
934 memcpy(ctx->cursor, &val, sizeof(val));
935 ctx->cursor += sizeof(src);
936
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930937 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700938}
939
Andrew Jeffery76712f62024-05-22 15:19:00 +0930940__attribute__((always_inline)) static inline int
941pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700942{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930943 assert(ctx);
944
945 if (!ctx->cursor) {
946 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700947 }
948
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930949 static_assert(
950 // NOLINTNEXTLINE(bugprone-sizeof-expression)
951 sizeof(src) < INTMAX_MAX,
952 "The following addition may not uphold the runtime assertion");
953 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
954 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930955 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930956 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700957 ctx->remaining -= sizeof(src);
958 assert(ctx->remaining >= 0);
959 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930960 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700961 }
962
963 memcpy(ctx->cursor, &src, sizeof(src));
964 ctx->cursor += sizeof(src);
965
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930966 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700967}
968
969#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930970 _Generic((src), \
971 uint8_t: pldm_msgbuf_insert_uint8, \
972 int8_t: pldm_msgbuf_insert_int8, \
973 uint16_t: pldm_msgbuf_insert_uint16, \
974 int16_t: pldm_msgbuf_insert_int16, \
975 uint32_t: pldm_msgbuf_insert_uint32, \
976 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700977
Andrew Jeffery76712f62024-05-22 15:19:00 +0930978__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930979// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
980pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, const void *src,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930981 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700982{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930983 assert(ctx);
984
985 if (!ctx->cursor || !src) {
986 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700987 }
988
989 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930990 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700991 }
992
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930993#if INTMAX_MAX < SIZE_MAX
994 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930995 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700996 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930997#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700998
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930999 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301000 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301001 }
1002 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001003 assert(ctx->remaining >= 0);
1004 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301005 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001006 }
1007
Andrew Jefferya065ecc2023-10-27 15:02:11 +10301008 memcpy(ctx->cursor, src, count);
1009 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001010
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301011 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001012}
1013
Andrew Jeffery1c571442024-07-08 10:25:48 +09301014__attribute__((always_inline)) static inline int
1015pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, const char *src,
1016 size_t count)
1017{
1018 return pldm__msgbuf_insert_array_void(ctx, src, count);
1019}
1020
1021__attribute__((always_inline)) static inline int
1022pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
1023 size_t count)
1024{
1025 return pldm__msgbuf_insert_array_void(ctx, src, count);
1026}
1027
Thu Nguyen062c8762023-04-22 20:45:04 +07001028#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +09301029 _Generic((*(src)), \
1030 uint8_t: pldm_msgbuf_insert_array_uint8, \
1031 char: pldm_msgbuf_insert_array_char)(dst, src, count)
Thu Nguyen062c8762023-04-22 20:45:04 +07001032
Andrew Jeffery76712f62024-05-22 15:19:00 +09301033__attribute__((always_inline)) static inline int
1034pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
1035 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +07001036{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301037 assert(ctx);
1038
1039 if (!ctx->cursor || !cursor || *cursor) {
1040 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001041 }
1042
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301043#if INTMAX_MAX < SIZE_MAX
1044 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301045 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001046 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301047#endif
Thu Nguyen062c8762023-04-22 20:45:04 +07001048
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301049 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301050 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301051 }
1052 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +07001053 assert(ctx->remaining >= 0);
1054 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301055 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001056 }
1057
1058 *cursor = ctx->cursor;
1059 ctx->cursor += required;
1060
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301061 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001062}
1063
Andrew Jeffery76712f62024-05-22 15:19:00 +09301064__attribute__((always_inline)) static inline int
Thu Nguyen9c83d682024-07-02 08:43:09 +00001065pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
1066 size_t *length)
1067{
1068 intmax_t measured;
1069
1070 assert(ctx);
1071
1072 if (!ctx->cursor || (cursor && *cursor)) {
1073 return pldm_msgbuf_status(ctx, EINVAL);
1074 }
1075
1076 if (ctx->remaining < 0) {
1077 /* Tracking the amount of overflow gets disturbed here */
1078 return pldm_msgbuf_status(ctx, EOVERFLOW);
1079 }
1080
1081 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1082 if (measured == ctx->remaining) {
1083 /*
1084 * We have hit the end of the buffer prior to the NUL terminator.
1085 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
1086 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1087 * return an error.
1088 */
1089 ctx->remaining = -1;
1090 return pldm_msgbuf_status(ctx, EOVERFLOW);
1091 }
1092
1093 /* Include the NUL terminator in the span length, as spans are opaque */
1094 measured++;
1095
1096 if (ctx->remaining < INTMAX_MIN + measured) {
1097 return pldm_msgbuf_status(ctx, EOVERFLOW);
1098 }
1099
1100 ctx->remaining -= measured;
1101 assert(ctx->remaining >= 0);
1102 if (ctx->remaining < 0) {
1103 return pldm_msgbuf_status(ctx, EOVERFLOW);
1104 }
1105
1106 if (cursor) {
1107 *cursor = ctx->cursor;
1108 }
1109
1110 ctx->cursor += measured;
1111
1112 if (length) {
1113 *length = measured;
1114 }
1115
1116 return 0;
1117}
1118
1119__attribute__((always_inline)) static inline int
Thu Nguyen15237782024-07-02 09:30:41 +00001120pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1121 size_t *length)
1122{
1123 static const char16_t term = 0;
1124 ptrdiff_t measured;
1125 void *end;
1126
1127 assert(ctx);
1128
1129 if (!ctx->cursor || (cursor && *cursor)) {
1130 return pldm_msgbuf_status(ctx, EINVAL);
1131 }
1132
1133 if (ctx->remaining < 0) {
1134 /* Tracking the amount of overflow gets disturbed here */
1135 return pldm_msgbuf_status(ctx, EOVERFLOW);
1136 }
1137
1138 /*
1139 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1140 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1141 * start of the string
1142 */
1143 end = (char *)ctx->cursor;
1144 do {
1145 if (end != ctx->cursor) {
1146 /*
1147 * If we've looped we've found a relatively-unaligned NUL code-point.
1148 * Scan again from a relatively-aligned start point.
1149 */
1150 end = (char *)end + 1;
1151 }
1152 measured = (char *)end - (char *)ctx->cursor;
1153 end = (char *)memmem(end, ctx->remaining - measured, &term,
1154 sizeof(term));
1155 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1156
1157 if (!end) {
1158 /*
1159 * Optimistically, the last required pattern byte was one beyond the end of
1160 * the buffer. Setting ctx->remaining negative ensures the
1161 * `pldm_msgbuf_destroy*()` APIs also return an error.
1162 */
1163 ctx->remaining = -1;
1164 return pldm_msgbuf_status(ctx, EOVERFLOW);
1165 }
1166
1167 end = (char *)end + sizeof(char16_t);
1168 measured = (char *)end - (char *)ctx->cursor;
1169
1170#if INTMAX_MAX < PTRDIFF_MAX
1171 if (measured >= INTMAX_MAX) {
1172 return pldm_msgbuf_status(ctx, EOVERFLOW);
1173 }
1174#endif
1175
1176 if (ctx->remaining < INTMAX_MIN + (intmax_t)measured) {
1177 assert(ctx->remaining < 0);
1178 return pldm_msgbuf_status(ctx, EOVERFLOW);
1179 }
1180
1181 ctx->remaining -= (intmax_t)measured;
1182 assert(ctx->remaining >= 0);
1183 if (ctx->remaining < 0) {
1184 return pldm_msgbuf_status(ctx, EOVERFLOW);
1185 }
1186
1187 if (cursor) {
1188 *cursor = ctx->cursor;
1189 }
1190
1191 ctx->cursor += measured;
1192
1193 if (length) {
1194 *length = (size_t)measured;
1195 }
1196
1197 return 0;
1198}
1199
1200__attribute__((always_inline)) static inline int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301201pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001202{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301203 assert(ctx);
1204
1205 if (!ctx->cursor || !cursor || *cursor || !len) {
1206 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001207 }
1208
1209 assert(ctx->remaining >= 0);
1210 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301211 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001212 }
1213
1214 *cursor = ctx->cursor;
1215 ctx->cursor += ctx->remaining;
1216 *len = ctx->remaining;
1217 ctx->remaining = 0;
1218
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301219 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001220}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001221
1222/**
1223 * @brief pldm_msgbuf copy data between two msg buffers
1224 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301225 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1226 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001227 * @param[in] size - size of data to be copied
1228 * @param[in] description - description of data copied
1229 *
1230 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1231 * PLDM_ERROR_INVALID_LENGTH otherwise.
1232 * PLDM_ERROR_INVALID_DATA if input is invalid
1233 */
1234#define pldm_msgbuf_copy(dst, src, type, name) \
1235 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301236__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001237// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301238pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
1239 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001240{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301241 assert(src);
1242 assert(dst);
1243 assert(src->mode == dst->mode);
1244
1245 if (!src->cursor || !dst->cursor || !description) {
1246 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001247 }
1248
1249#if INTMAX_MAX < SIZE_MAX
1250 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301251 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001252 }
1253#endif
1254
1255 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301256 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001257 }
1258
1259 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301260 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001261 }
1262
1263 src->remaining -= (intmax_t)size;
1264 assert(src->remaining >= 0);
1265 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301266 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001267 }
1268
1269 dst->remaining -= (intmax_t)size;
1270 assert(dst->remaining >= 0);
1271 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301272 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001273 }
1274
1275 memcpy(dst->cursor, src->cursor, size);
1276 src->cursor += size;
1277 dst->cursor += size;
1278
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301279 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001280}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301281
Andrew Jeffery8b879602024-07-08 12:50:19 +09301282__attribute__((always_inline)) static inline int
1283pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1284{
1285 void *ascii = NULL;
1286 size_t len = 0;
1287 int rc;
1288
1289 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1290 if (rc < 0) {
1291 return rc;
1292 }
1293
1294 return pldm__msgbuf_insert_array_void(dst, ascii, len);
1295}
1296
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301297__attribute__((always_inline)) static inline int
1298pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1299{
1300 void *utf16 = NULL;
1301 size_t len = 0;
1302 int rc;
1303
1304 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1305 if (rc < 0) {
1306 return rc;
1307 }
1308
1309 return pldm__msgbuf_insert_array_void(dst, utf16, len);
1310}
1311
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301312#ifdef __cplusplus
1313}
1314#endif
1315
Andrew Jeffery66c77232024-04-24 11:42:02 +09301316#ifdef __cplusplus
1317#include <type_traits>
1318
1319template <typename T>
1320static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1321 void *buf)
1322{
1323 static_assert(std::is_same<uint8_t *, T>::value);
1324 return pldm__msgbuf_extract_uint8(ctx, buf);
1325}
1326
1327template <typename T>
1328static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1329 void *buf)
1330{
1331 static_assert(std::is_same<int8_t *, T>::value);
1332 return pldm__msgbuf_extract_int8(ctx, buf);
1333}
1334
1335template <typename T>
1336static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1337 void *buf)
1338{
1339 static_assert(std::is_same<uint16_t *, T>::value);
1340 return pldm__msgbuf_extract_uint16(ctx, buf);
1341}
1342
1343template <typename T>
1344static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1345 void *buf)
1346{
1347 static_assert(std::is_same<int16_t *, T>::value);
1348 return pldm__msgbuf_extract_int16(ctx, buf);
1349}
1350
1351template <typename T>
1352static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1353 void *buf)
1354{
1355 static_assert(std::is_same<uint32_t *, T>::value);
1356 return pldm__msgbuf_extract_uint32(ctx, buf);
1357}
1358
1359template <typename T>
1360static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1361 void *buf)
1362{
1363 static_assert(std::is_same<int32_t *, T>::value);
1364 return pldm__msgbuf_extract_int32(ctx, buf);
1365}
1366
1367template <typename T>
1368static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1369 void *buf)
1370{
1371 static_assert(std::is_same<real32_t *, T>::value);
1372 return pldm__msgbuf_extract_real32(ctx, buf);
1373}
1374#endif
1375
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301376#endif /* BUF_H */