blob: 16e3680d7b718e132c3b89ef6d759685b1ee6515 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10302#ifndef PLDM_MSGBUF_H
3#define PLDM_MSGBUF_H
4
Andrew Jeffery860a43d2024-08-23 01:21:58 +00005#include "compiler.h"
6
Andrew Jeffery66c77232024-04-24 11:42:02 +09307/*
8 * Historically, many of the structs exposed in libpldm's public headers are
9 * defined with __attribute__((packed)). This is unfortunate: it gives the
10 * impression that a wire-format buffer can be cast to the message type to make
11 * the message's fields easily accessible. As it turns out, that's not
12 * that's valid for several reasons:
13 *
14 * 1. Casting the wire-format buffer to a struct of the message type doesn't
15 * abstract the endianness of message field values
16 *
17 * 2. Some messages contain packed tagged union fields which cannot be properly
18 * described in a C struct.
19 *
20 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
21 * that is type-safe, spatially memory-safe, endian-safe, performant, and
22 * free of undefined-behaviour. Message structs that are added to the public
23 * library API should no-longer be marked __attribute__((packed)), and the
24 * implementation of their encode and decode functions must exploit the msgbuf
25 * API.
26 *
27 * However, we would like to allow implementation of codec functions in terms of
28 * msgbuf APIs even if they're decoding a message into a (historically) packed
29 * struct. Some of the complexity that follows is a consequence of the packed/
30 * unpacked conflict.
31 */
32
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103033#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093034/*
35 * Fix up C11's _Static_assert() vs C++'s static_assert().
36 *
37 * Can we please have nice things for once.
38 */
39// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
40#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103041extern "C" {
42#endif
43
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103044#include <libpldm/base.h>
45#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103046
Andrew Jeffery66c77232024-04-24 11:42:02 +093047#include "compiler.h"
48
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103049#include <assert.h>
50#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093051#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103052#include <limits.h>
53#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093054#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103055#include <string.h>
56#include <sys/types.h>
Thu Nguyen15237782024-07-02 09:30:41 +000057#include <uchar.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103058
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093059/*
60 * We can't use static_assert() outside of some other C construct. Deal
61 * with high-level global assertions by burying them in an unused struct
62 * declaration, that has a sole member for compliance with the requirement that
63 * types must have a size.
64*/
65static struct {
66 static_assert(
67 INTMAX_MAX != SIZE_MAX,
68 "Extraction and insertion value comparisons may be broken");
69 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
70 "Extraction and insertion arithmetic may be broken");
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093071 static_assert(PLDM_SUCCESS == 0, "Error handling is broken");
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093072 int compliance;
Andrew Jeffery860a43d2024-08-23 01:21:58 +000073} build_assertions LIBPLDM_CC_UNUSED;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093074
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093075enum pldm_msgbuf_error_mode {
76 PLDM_MSGBUF_PLDM_CC = 0x5a,
77 PLDM_MSGBUF_C_ERRNO = 0xa5,
78};
79
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103080struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070081 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093082 intmax_t remaining;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093083 enum pldm_msgbuf_error_mode mode;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103084};
85
Andrew Jefferyd861a682024-06-03 21:43:09 +093086/**
87 * @brief Either negate an errno value or return a value mapped to a PLDM
88 * completion code.
89 *
90 * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API
91 * for ergonomics. It's preferred that we don't try to unify this with
92 * `pldm_xlate_errno()` from src/api.h despite the similarities.
93 *
94 * @param[in] ctx - The msgbuf context providing the personality info
95 * @param[in] err - The positive errno value to translate
96 *
97 * @return Either the negated value of @p err if the context's error mode is
98 * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the
99 * error mode is `PLDM_MSGBUF_PLDM_CC`.
100 */
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930101__attribute__((always_inline)) static inline int
102pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err)
103{
104 int rc;
105
106 assert(err != 0);
107 assert(err <= INT_MAX);
108
109 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
110 if (err > INT_MAX) {
111 return -EINVAL;
112 }
113
114 static_assert(INT_MIN + INT_MAX < 0,
115 "Arithmetic assumption failure");
116 return -((int)err);
117 }
118
119 if (err > INT_MAX) {
120 return PLDM_ERROR;
121 }
122
123 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
124 switch (err) {
125 case EINVAL:
126 rc = PLDM_ERROR_INVALID_DATA;
127 break;
128 case EBADMSG:
129 case EOVERFLOW:
130 rc = PLDM_ERROR_INVALID_LENGTH;
131 break;
132 default:
133 assert(false);
134 rc = PLDM_ERROR;
135 break;
136 }
137
138 assert(rc > 0);
139 return rc;
140}
141
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030142/**
143 * @brief Initialize pldm buf struct for buf extractor
144 *
145 * @param[out] ctx - pldm_msgbuf context for extractor
146 * @param[in] minsize - The minimum required length of buffer `buf`
147 * @param[in] buf - buffer to be extracted
148 * @param[in] len - size of buffer
149 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930150 * @return 0 on success, otherwise an error code appropriate for the current
151 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030152 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930153__attribute__((always_inline)) static inline int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930154// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
155pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
156 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030157{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930158 assert(ctx);
159 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
160 ctx->mode == PLDM_MSGBUF_C_ERRNO);
161
162 if (!buf) {
163 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030164 }
165
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930166 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930167 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030168 }
169
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930170#if INTMAX_MAX < SIZE_MAX
171 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930172 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930173 }
174#endif
175
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930176 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930177 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030178 }
179
180 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930181 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030182
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930183 return 0;
184}
185
186/**
187 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
188 *
189 * @see pldm__msgbuf_init
190 *
191 * @param[out] ctx - pldm_msgbuf context for extractor
192 * @param[in] minsize - The minimum required length of buffer `buf`
193 * @param[in] buf - buffer to be extracted
194 * @param[in] len - size of buffer
195 *
196 * @return PLDM_SUCCESS if the provided buffer region is sensible,
197 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
198 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
199 */
200__attribute__((always_inline)) static inline int
201pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
202 size_t len)
203{
204 if (!ctx) {
205 return PLDM_ERROR_INVALID_DATA;
206 }
207
208 ctx->mode = PLDM_MSGBUF_PLDM_CC;
209 return pldm__msgbuf_init(ctx, minsize, buf, len);
210}
211
212/**
213 * @brief Initialise a msgbuf instance to return errors as negative errno values
214 *
215 * @see pldm__msgbuf_init
216 *
217 * @param[out] ctx - pldm_msgbuf context for extractor
218 * @param[in] minsize - The minimum required length of buffer `buf`
219 * @param[in] buf - buffer to be extracted
220 * @param[in] len - size of buffer
221 *
222 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
223 * pointer parameters are invalid, or -EOVERFLOW if length constraints
224 * are violated.
225 */
226__attribute__((always_inline)) static inline int
227pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
228 size_t len)
229{
230 if (!ctx) {
231 return -EINVAL;
232 }
233
234 ctx->mode = PLDM_MSGBUF_C_ERRNO;
235 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030236}
237
238/**
239 * @brief Validate buffer overflow state
240 *
241 * @param[in] ctx - pldm_msgbuf context for extractor
242 *
243 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
244 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
245 * prior accesses would have occurred beyond the bounds of the buffer, and
246 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
247 * pointer.
248 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930249__attribute__((always_inline)) static inline int
250pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030251{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930252 assert(ctx);
253 if (ctx->remaining < 0) {
254 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030255 }
256
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930257 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030258}
259
260/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930261 * @brief Test whether a message buffer has been exactly consumed
262 *
263 * @param[in] ctx - pldm_msgbuf context for extractor
264 *
265 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
266 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
267 * indicates that an incorrect sequence of accesses have occurred, and
268 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
269 * pointer.
270 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930271__attribute__((always_inline)) static inline int
272pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930273{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930274 assert(ctx);
275 if (ctx->remaining != 0) {
276 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930277 }
278
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930279 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930280}
281
282/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030283 * @brief Destroy the pldm buf
284 *
285 * @param[in] ctx - pldm_msgbuf context for extractor
286 *
287 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
288 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
289 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
290 * bounds of the buffer.
291 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930292__attribute__((always_inline)) static inline int
293pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030294{
295 int valid;
296
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930297 assert(ctx);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030298 valid = pldm_msgbuf_validate(ctx);
299
300 ctx->cursor = NULL;
301 ctx->remaining = 0;
302
303 return valid;
304}
305
306/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930307 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
308 * has been completely consumed without overflow
309 *
310 * @param[in] ctx - pldm_msgbuf context
311 *
312 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
313 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
314 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
315 * have occurred byond the bounds of the buffer
316 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930317__attribute__((always_inline)) static inline int
318pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930319{
320 int consumed;
321
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930322 assert(ctx);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930323 consumed = pldm_msgbuf_consumed(ctx);
324
325 ctx->cursor = NULL;
326 ctx->remaining = 0;
327
328 return consumed;
329}
330
Andrew Jeffery66c77232024-04-24 11:42:02 +0930331/*
332 * Exploit the pre-processor to perform type checking by macro substitution.
333 *
334 * A C type is defined by its alignment as well as its object
335 * size, and compilers have a hammer to enforce it in the form of
336 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
337 * the libpldm public API this presents a problem: Naively attempting to use the
338 * msgbuf APIs on a member of a packed struct would yield an error.
339 *
340 * The msgbuf APIs are implemented such that data is moved through unaligned
341 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
342 * make the object pointers take a trip through `void *` at its API boundary.
343 * That presents a bit too much of an opportunity to non-surgically remove your
344 * own foot, so here we set about doing something to mitigate that as well.
345 *
346 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
347 * only for the purpose of object sizes, disregarding alignment. We have a few
348 * constraints that cause some headaches:
349 *
350 * 1. We have to perform the type-check before a call through a C function,
351 * as the function must take the object pointer argument as `void *`.
352 * Essentially, this constrains us to doing something with macros.
353 *
354 * 2. While libpldm is a C library, its test suite is written in C++ to take
355 * advantage of gtest.
356 *
357 * 3. Ideally we'd do something with C's `static_assert()`, however
358 * `static_assert()` is defined as void, and as we're constrained to macros,
359 * using `static_assert()` would require a statement-expression
360 *
361 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
362 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
363 * the purpose of enabling statement-expressions in this one instance.
364 *
365 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
366 * however it's implemented in terms of `_Generic()`, which is not available
367 * in C++.
368 *
369 * Combined this means we need separate solutions for C and C++.
370 *
371 * For C, as we don't have statement-expressions, we need to exploit some other
372 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
373 * API function call. We also have to take care of the fact that the call-sites
374 * may be in the context of a variable assignment for error-handling purposes.
375 * The key observation is that we can use the comma operator as a sequence point
376 * to order the type check before the API call, discarding the "result" value of
377 * the type check and yielding the return value of the API call.
378 *
379 * C++ could be less of a headache than the C as we can leverage template
380 * functions. An advantage of template functions is that while their definition
381 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530382 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930383 * we have in the C path. However, the use of the msgbuf APIs in the test suite
384 * still makes things somewhat tricky, as the call-sites in the test suite are
385 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
386 * takes both the object type and the required type as template arguments, and
387 * then define the object pointer parameter as `void *` for a call through to
388 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
389 * encapsulated in gtest macros, use of commas in the template specification
390 * causes pre-processor confusion. In this way we're constrained to only one
391 * template argument per function.
392 *
393 * Implement the C++ path using template functions that take the destination
394 * object type as a template argument, while the name of the function symbols
395 * are derived from the required type. The manual implementations of these
396 * appear at the end of the header. The type safety is actually enforced
397 * by `static_assert()` this time, as we can use statements as we're not
398 * constrained to an expression in the templated function body.
399 *
400 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
401 * double-evaluation of some arguments. We're not yet bothered by this for two
402 * reasons:
403 *
404 * 1. The nature of the current call-sites are such that there are no
405 * argument expressions that result in undesirable side-effects
406 *
407 * 2. It's an API internal to the libpldm implementation, and we can fix things
408 * whenever something crops up the violates the observation in 1.
409 */
410#ifdef __cplusplus
411#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
412 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
413#else
414#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
415 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
416#endif
417
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930418/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030419 * @brief pldm_msgbuf extractor for a uint8_t
420 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530421 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030422 * @param[out] dst - destination of extracted value
423 *
424 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
425 * PLDM_ERROR_INVALID_LENGTH otherwise.
426 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
427 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930428#define pldm_msgbuf_extract_uint8(ctx, dst) \
429 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
430 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930431__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930432// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930433pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030434{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930435 assert(ctx);
436
437 if (!ctx->cursor || !dst) {
438 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030439 }
440
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930441 if (ctx->remaining == INTMAX_MIN) {
442 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930443 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930444 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930445 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030446 assert(ctx->remaining >= 0);
447 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930448 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030449 }
450
Andrew Jeffery66c77232024-04-24 11:42:02 +0930451 memcpy(dst, ctx->cursor, sizeof(uint8_t));
452
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030453 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930454 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030455}
456
Andrew Jeffery66c77232024-04-24 11:42:02 +0930457#define pldm_msgbuf_extract_int8(ctx, dst) \
458 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
459 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930460__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930461// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930462pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030463{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930464 assert(ctx);
465
466 if (!ctx->cursor || !dst) {
467 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030468 }
469
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930470 if (ctx->remaining == INTMAX_MIN) {
471 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930472 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930473 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930474 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030475 assert(ctx->remaining >= 0);
476 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930477 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030478 }
479
Andrew Jeffery66c77232024-04-24 11:42:02 +0930480 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030481 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930482 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030483}
484
Andrew Jeffery66c77232024-04-24 11:42:02 +0930485#define pldm_msgbuf_extract_uint16(ctx, dst) \
486 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
487 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930488__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930489// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930490pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030491{
492 uint16_t ldst;
493
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930494 assert(ctx);
495
496 if (!ctx->cursor || !dst) {
497 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030498 }
499
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930500 // Check for underflow while tracking the magnitude of the buffer overflow
501 static_assert(
502 // NOLINTNEXTLINE(bugprone-sizeof-expression)
503 sizeof(ldst) < INTMAX_MAX,
504 "The following addition may not uphold the runtime assertion");
505 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
506 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930507 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930508 }
509
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030510 // Check for buffer overflow. If we overflow, account for the request as
511 // negative values in ctx->remaining. This way we can debug how far
512 // we've overflowed.
513 ctx->remaining -= sizeof(ldst);
514
515 // Prevent the access if it would overflow. First, assert so we blow up
516 // the test suite right at the point of failure. However, cater to
517 // -DNDEBUG by explicitly testing that the access is valid.
518 assert(ctx->remaining >= 0);
519 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930520 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030521 }
522
523 // Use memcpy() to have the compiler deal with any alignment
524 // issues on the target architecture
525 memcpy(&ldst, ctx->cursor, sizeof(ldst));
526
527 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930528 ldst = le16toh(ldst);
529
530 // Allow storing to unaligned
531 memcpy(dst, &ldst, sizeof(ldst));
532
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030533 ctx->cursor += sizeof(ldst);
534
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930535 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030536}
537
Andrew Jeffery66c77232024-04-24 11:42:02 +0930538#define pldm_msgbuf_extract_int16(ctx, dst) \
539 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
540 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930541__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930542// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930543pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030544{
545 int16_t ldst;
546
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930547 assert(ctx);
548
549 if (!ctx->cursor || !dst) {
550 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030551 }
552
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930553 static_assert(
554 // NOLINTNEXTLINE(bugprone-sizeof-expression)
555 sizeof(ldst) < INTMAX_MAX,
556 "The following addition may not uphold the runtime assertion");
557 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
558 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930559 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930560 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030561 ctx->remaining -= sizeof(ldst);
562 assert(ctx->remaining >= 0);
563 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930564 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030565 }
566
567 memcpy(&ldst, ctx->cursor, sizeof(ldst));
568
Andrew Jeffery66c77232024-04-24 11:42:02 +0930569 ldst = le16toh(ldst);
570 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030571 ctx->cursor += sizeof(ldst);
572
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930573 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030574}
575
Andrew Jeffery66c77232024-04-24 11:42:02 +0930576#define pldm_msgbuf_extract_uint32(ctx, dst) \
577 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
578 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930579__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930580// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930581pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030582{
583 uint32_t ldst;
584
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930585 assert(ctx);
586
587 if (!ctx->cursor || !dst) {
588 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030589 }
590
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930591 static_assert(
592 // NOLINTNEXTLINE(bugprone-sizeof-expression)
593 sizeof(ldst) < INTMAX_MAX,
594 "The following addition may not uphold the runtime assertion");
595 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
596 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930597 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930598 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030599 ctx->remaining -= sizeof(ldst);
600 assert(ctx->remaining >= 0);
601 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930602 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030603 }
604
605 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930606 ldst = le32toh(ldst);
607 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030608 ctx->cursor += sizeof(ldst);
609
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930610 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030611}
612
Andrew Jeffery66c77232024-04-24 11:42:02 +0930613#define pldm_msgbuf_extract_int32(ctx, dst) \
614 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
615 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930616__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930617// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930618pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030619{
620 int32_t ldst;
621
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930622 assert(ctx);
623
624 if (!ctx->cursor || !dst) {
625 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030626 }
627
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930628 static_assert(
629 // NOLINTNEXTLINE(bugprone-sizeof-expression)
630 sizeof(ldst) < INTMAX_MAX,
631 "The following addition may not uphold the runtime assertion");
632 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
633 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930634 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930635 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030636 ctx->remaining -= sizeof(ldst);
637 assert(ctx->remaining >= 0);
638 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930639 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030640 }
641
642 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930643 ldst = le32toh(ldst);
644 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030645 ctx->cursor += sizeof(ldst);
646
647 return PLDM_SUCCESS;
648}
649
Andrew Jeffery66c77232024-04-24 11:42:02 +0930650#define pldm_msgbuf_extract_real32(ctx, dst) \
651 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
652 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930653__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930654// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930655pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030656{
657 uint32_t ldst;
658
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930659 static_assert(sizeof(real32_t) == sizeof(ldst),
660 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930661
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930662 assert(ctx);
663
664 if (!ctx->cursor || !dst) {
665 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030666 }
667
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930668 static_assert(
669 // NOLINTNEXTLINE(bugprone-sizeof-expression)
670 sizeof(ldst) < INTMAX_MAX,
671 "The following addition may not uphold the runtime assertion");
672 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
673 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930674 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930675 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030676 ctx->remaining -= sizeof(ldst);
677 assert(ctx->remaining >= 0);
678 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930679 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030680 }
681
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030682 memcpy(&ldst, ctx->cursor, sizeof(ldst));
683 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930684 memcpy(dst, &ldst, sizeof(ldst));
685 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030686
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930687 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030688}
689
Andrew Jeffery66c77232024-04-24 11:42:02 +0930690/**
691 * Extract the field at the msgbuf cursor into the lvalue named by dst.
692 *
693 * @param ctx The msgbuf context object
694 * @param dst The lvalue into which the field at the msgbuf cursor should be
695 * extracted
696 *
697 * @return PLDM_SUCCESS on success, otherwise another value on error
698 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030699#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930700 _Generic((dst), \
701 uint8_t: pldm__msgbuf_extract_uint8, \
702 int8_t: pldm__msgbuf_extract_int8, \
703 uint16_t: pldm__msgbuf_extract_uint16, \
704 int16_t: pldm__msgbuf_extract_int16, \
705 uint32_t: pldm__msgbuf_extract_uint32, \
706 int32_t: pldm__msgbuf_extract_int32, \
707 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
708
709/**
710 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
711 *
712 * @param ctx The msgbuf context object
713 * @param dst The pointer to the object into which the field at the msgbuf
714 * cursor should be extracted
715 *
716 * @return PLDM_SUCCESS on success, otherwise another value on error
717 */
718#define pldm_msgbuf_extract_p(ctx, dst) \
719 _Generic((dst), \
720 uint8_t *: pldm__msgbuf_extract_uint8, \
721 int8_t *: pldm__msgbuf_extract_int8, \
722 uint16_t *: pldm__msgbuf_extract_uint16, \
723 int16_t *: pldm__msgbuf_extract_int16, \
724 uint32_t *: pldm__msgbuf_extract_uint32, \
725 int32_t *: pldm__msgbuf_extract_int32, \
726 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030727
Andrew Jeffery76712f62024-05-22 15:19:00 +0930728__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930729// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
730pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, void *dst,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930731 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930732{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930733 assert(ctx);
734
735 if (!ctx->cursor || !dst) {
736 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930737 }
738
739 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930740 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930741 }
742
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930743#if INTMAX_MAX < SIZE_MAX
744 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930745 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930746 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930747#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930748
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930749 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930750 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930751 }
752 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930753 assert(ctx->remaining >= 0);
754 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930755 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930756 }
757
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030758 memcpy(dst, ctx->cursor, count);
759 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930760
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930761 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930762}
763
Andrew Jeffery1c571442024-07-08 10:25:48 +0930764__attribute__((always_inline)) static inline int
765pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, char *dst, size_t count)
766{
767 return pldm__msgbuf_extract_array_void(ctx, dst, count);
768}
769
770__attribute__((always_inline)) static inline int
771pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
772 size_t count)
773{
774 return pldm__msgbuf_extract_array_void(ctx, dst, count);
775}
776
Andrew Jeffery369b1212023-04-20 15:44:48 +0930777#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930778 _Generic((*(dst)), \
779 uint8_t: pldm_msgbuf_extract_array_uint8, \
780 char: pldm_msgbuf_extract_array_char)(ctx, dst, count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930781
Andrew Jeffery76712f62024-05-22 15:19:00 +0930782__attribute__((always_inline)) static inline int
783pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700784{
785 uint32_t val = htole32(src);
786
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930787 assert(ctx);
788
789 if (!ctx->cursor) {
790 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700791 }
792
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930793 static_assert(
794 // NOLINTNEXTLINE(bugprone-sizeof-expression)
795 sizeof(src) < INTMAX_MAX,
796 "The following addition may not uphold the runtime assertion");
797 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
798 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930799 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930800 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700801 ctx->remaining -= sizeof(src);
802 assert(ctx->remaining >= 0);
803 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930804 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700805 }
806
807 memcpy(ctx->cursor, &val, sizeof(val));
808 ctx->cursor += sizeof(src);
809
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930810 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700811}
812
Andrew Jeffery76712f62024-05-22 15:19:00 +0930813__attribute__((always_inline)) static inline int
814pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700815{
816 uint16_t val = htole16(src);
817
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930818 assert(ctx);
819
820 if (!ctx->cursor) {
821 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700822 }
823
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930824 static_assert(
825 // NOLINTNEXTLINE(bugprone-sizeof-expression)
826 sizeof(src) < INTMAX_MAX,
827 "The following addition may not uphold the runtime assertion");
828 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
829 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930830 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930831 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700832 ctx->remaining -= sizeof(src);
833 assert(ctx->remaining >= 0);
834 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930835 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700836 }
837
838 memcpy(ctx->cursor, &val, sizeof(val));
839 ctx->cursor += sizeof(src);
840
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930841 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700842}
843
Andrew Jeffery76712f62024-05-22 15:19:00 +0930844__attribute__((always_inline)) static inline int
845pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700846{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930847 assert(ctx);
848
849 if (!ctx->cursor) {
850 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700851 }
852
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930853 static_assert(
854 // NOLINTNEXTLINE(bugprone-sizeof-expression)
855 sizeof(src) < INTMAX_MAX,
856 "The following addition may not uphold the runtime assertion");
857 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
858 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930859 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930860 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700861 ctx->remaining -= sizeof(src);
862 assert(ctx->remaining >= 0);
863 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930864 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700865 }
866
867 memcpy(ctx->cursor, &src, sizeof(src));
868 ctx->cursor += sizeof(src);
869
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930870 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700871}
872
Andrew Jeffery76712f62024-05-22 15:19:00 +0930873__attribute__((always_inline)) static inline int
874pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700875{
876 int32_t val = htole32(src);
877
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930878 assert(ctx);
879
880 if (!ctx->cursor) {
881 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700882 }
883
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930884 static_assert(
885 // NOLINTNEXTLINE(bugprone-sizeof-expression)
886 sizeof(src) < INTMAX_MAX,
887 "The following addition may not uphold the runtime assertion");
888 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
889 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930890 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930891 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700892 ctx->remaining -= sizeof(src);
893 assert(ctx->remaining >= 0);
894 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930895 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700896 }
897
898 memcpy(ctx->cursor, &val, sizeof(val));
899 ctx->cursor += sizeof(src);
900
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930901 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700902}
903
Andrew Jeffery76712f62024-05-22 15:19:00 +0930904__attribute__((always_inline)) static inline int
905pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700906{
907 int16_t val = htole16(src);
908
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930909 assert(ctx);
910
911 if (!ctx->cursor) {
912 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700913 }
914
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930915 static_assert(
916 // NOLINTNEXTLINE(bugprone-sizeof-expression)
917 sizeof(src) < INTMAX_MAX,
918 "The following addition may not uphold the runtime assertion");
919 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
920 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930921 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930922 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700923 ctx->remaining -= sizeof(src);
924 assert(ctx->remaining >= 0);
925 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930926 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700927 }
928
929 memcpy(ctx->cursor, &val, sizeof(val));
930 ctx->cursor += sizeof(src);
931
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930932 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700933}
934
Andrew Jeffery76712f62024-05-22 15:19:00 +0930935__attribute__((always_inline)) static inline int
936pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700937{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930938 assert(ctx);
939
940 if (!ctx->cursor) {
941 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700942 }
943
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930944 static_assert(
945 // NOLINTNEXTLINE(bugprone-sizeof-expression)
946 sizeof(src) < INTMAX_MAX,
947 "The following addition may not uphold the runtime assertion");
948 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
949 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930950 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930951 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700952 ctx->remaining -= sizeof(src);
953 assert(ctx->remaining >= 0);
954 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930955 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700956 }
957
958 memcpy(ctx->cursor, &src, sizeof(src));
959 ctx->cursor += sizeof(src);
960
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930961 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700962}
963
964#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930965 _Generic((src), \
966 uint8_t: pldm_msgbuf_insert_uint8, \
967 int8_t: pldm_msgbuf_insert_int8, \
968 uint16_t: pldm_msgbuf_insert_uint16, \
969 int16_t: pldm_msgbuf_insert_int16, \
970 uint32_t: pldm_msgbuf_insert_uint32, \
971 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700972
Andrew Jeffery76712f62024-05-22 15:19:00 +0930973__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930974// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
975pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, const void *src,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930976 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700977{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930978 assert(ctx);
979
980 if (!ctx->cursor || !src) {
981 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700982 }
983
984 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930985 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700986 }
987
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930988#if INTMAX_MAX < SIZE_MAX
989 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930990 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700991 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930992#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700993
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930994 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930995 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930996 }
997 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700998 assert(ctx->remaining >= 0);
999 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301000 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001001 }
1002
Andrew Jefferya065ecc2023-10-27 15:02:11 +10301003 memcpy(ctx->cursor, src, count);
1004 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001005
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301006 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001007}
1008
Andrew Jeffery1c571442024-07-08 10:25:48 +09301009__attribute__((always_inline)) static inline int
1010pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, const char *src,
1011 size_t count)
1012{
1013 return pldm__msgbuf_insert_array_void(ctx, src, count);
1014}
1015
1016__attribute__((always_inline)) static inline int
1017pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
1018 size_t count)
1019{
1020 return pldm__msgbuf_insert_array_void(ctx, src, count);
1021}
1022
Thu Nguyen062c8762023-04-22 20:45:04 +07001023#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +09301024 _Generic((*(src)), \
1025 uint8_t: pldm_msgbuf_insert_array_uint8, \
1026 char: pldm_msgbuf_insert_array_char)(dst, src, count)
Thu Nguyen062c8762023-04-22 20:45:04 +07001027
Andrew Jeffery76712f62024-05-22 15:19:00 +09301028__attribute__((always_inline)) static inline int
1029pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
1030 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +07001031{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301032 assert(ctx);
1033
1034 if (!ctx->cursor || !cursor || *cursor) {
1035 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001036 }
1037
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301038#if INTMAX_MAX < SIZE_MAX
1039 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301040 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001041 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301042#endif
Thu Nguyen062c8762023-04-22 20:45:04 +07001043
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301044 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301045 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301046 }
1047 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +07001048 assert(ctx->remaining >= 0);
1049 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301050 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001051 }
1052
1053 *cursor = ctx->cursor;
1054 ctx->cursor += required;
1055
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301056 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001057}
1058
Andrew Jeffery76712f62024-05-22 15:19:00 +09301059__attribute__((always_inline)) static inline int
Thu Nguyen9c83d682024-07-02 08:43:09 +00001060pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
1061 size_t *length)
1062{
1063 intmax_t measured;
1064
1065 assert(ctx);
1066
1067 if (!ctx->cursor || (cursor && *cursor)) {
1068 return pldm_msgbuf_status(ctx, EINVAL);
1069 }
1070
1071 if (ctx->remaining < 0) {
1072 /* Tracking the amount of overflow gets disturbed here */
1073 return pldm_msgbuf_status(ctx, EOVERFLOW);
1074 }
1075
1076 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1077 if (measured == ctx->remaining) {
1078 /*
1079 * We have hit the end of the buffer prior to the NUL terminator.
1080 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
1081 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1082 * return an error.
1083 */
1084 ctx->remaining = -1;
1085 return pldm_msgbuf_status(ctx, EOVERFLOW);
1086 }
1087
1088 /* Include the NUL terminator in the span length, as spans are opaque */
1089 measured++;
1090
1091 if (ctx->remaining < INTMAX_MIN + measured) {
1092 return pldm_msgbuf_status(ctx, EOVERFLOW);
1093 }
1094
1095 ctx->remaining -= measured;
1096 assert(ctx->remaining >= 0);
1097 if (ctx->remaining < 0) {
1098 return pldm_msgbuf_status(ctx, EOVERFLOW);
1099 }
1100
1101 if (cursor) {
1102 *cursor = ctx->cursor;
1103 }
1104
1105 ctx->cursor += measured;
1106
1107 if (length) {
1108 *length = measured;
1109 }
1110
1111 return 0;
1112}
1113
1114__attribute__((always_inline)) static inline int
Thu Nguyen15237782024-07-02 09:30:41 +00001115pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1116 size_t *length)
1117{
1118 static const char16_t term = 0;
1119 ptrdiff_t measured;
1120 void *end;
1121
1122 assert(ctx);
1123
1124 if (!ctx->cursor || (cursor && *cursor)) {
1125 return pldm_msgbuf_status(ctx, EINVAL);
1126 }
1127
1128 if (ctx->remaining < 0) {
1129 /* Tracking the amount of overflow gets disturbed here */
1130 return pldm_msgbuf_status(ctx, EOVERFLOW);
1131 }
1132
1133 /*
1134 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1135 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1136 * start of the string
1137 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301138 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001139 do {
1140 if (end != ctx->cursor) {
1141 /*
1142 * If we've looped we've found a relatively-unaligned NUL code-point.
1143 * Scan again from a relatively-aligned start point.
1144 */
1145 end = (char *)end + 1;
1146 }
1147 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301148 end = memmem(end, ctx->remaining - measured, &term,
1149 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001150 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1151
1152 if (!end) {
1153 /*
1154 * Optimistically, the last required pattern byte was one beyond the end of
1155 * the buffer. Setting ctx->remaining negative ensures the
1156 * `pldm_msgbuf_destroy*()` APIs also return an error.
1157 */
1158 ctx->remaining = -1;
1159 return pldm_msgbuf_status(ctx, EOVERFLOW);
1160 }
1161
1162 end = (char *)end + sizeof(char16_t);
1163 measured = (char *)end - (char *)ctx->cursor;
1164
1165#if INTMAX_MAX < PTRDIFF_MAX
1166 if (measured >= INTMAX_MAX) {
1167 return pldm_msgbuf_status(ctx, EOVERFLOW);
1168 }
1169#endif
1170
1171 if (ctx->remaining < INTMAX_MIN + (intmax_t)measured) {
1172 assert(ctx->remaining < 0);
1173 return pldm_msgbuf_status(ctx, EOVERFLOW);
1174 }
1175
1176 ctx->remaining -= (intmax_t)measured;
1177 assert(ctx->remaining >= 0);
1178 if (ctx->remaining < 0) {
1179 return pldm_msgbuf_status(ctx, EOVERFLOW);
1180 }
1181
1182 if (cursor) {
1183 *cursor = ctx->cursor;
1184 }
1185
1186 ctx->cursor += measured;
1187
1188 if (length) {
1189 *length = (size_t)measured;
1190 }
1191
1192 return 0;
1193}
1194
1195__attribute__((always_inline)) static inline int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301196pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001197{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301198 assert(ctx);
1199
1200 if (!ctx->cursor || !cursor || *cursor || !len) {
1201 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001202 }
1203
1204 assert(ctx->remaining >= 0);
1205 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301206 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001207 }
1208
1209 *cursor = ctx->cursor;
1210 ctx->cursor += ctx->remaining;
1211 *len = ctx->remaining;
1212 ctx->remaining = 0;
1213
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301214 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001215}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001216
1217/**
1218 * @brief pldm_msgbuf copy data between two msg buffers
1219 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301220 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1221 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001222 * @param[in] size - size of data to be copied
1223 * @param[in] description - description of data copied
1224 *
1225 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1226 * PLDM_ERROR_INVALID_LENGTH otherwise.
1227 * PLDM_ERROR_INVALID_DATA if input is invalid
1228 */
1229#define pldm_msgbuf_copy(dst, src, type, name) \
1230 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301231__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001232// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301233pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
1234 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001235{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301236 assert(src);
1237 assert(dst);
1238 assert(src->mode == dst->mode);
1239
1240 if (!src->cursor || !dst->cursor || !description) {
1241 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001242 }
1243
1244#if INTMAX_MAX < SIZE_MAX
1245 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301246 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001247 }
1248#endif
1249
1250 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301251 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001252 }
1253
1254 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301255 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001256 }
1257
1258 src->remaining -= (intmax_t)size;
1259 assert(src->remaining >= 0);
1260 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301261 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001262 }
1263
1264 dst->remaining -= (intmax_t)size;
1265 assert(dst->remaining >= 0);
1266 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301267 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001268 }
1269
1270 memcpy(dst->cursor, src->cursor, size);
1271 src->cursor += size;
1272 dst->cursor += size;
1273
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301274 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001275}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301276
Andrew Jeffery8b879602024-07-08 12:50:19 +09301277__attribute__((always_inline)) static inline int
1278pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1279{
1280 void *ascii = NULL;
1281 size_t len = 0;
1282 int rc;
1283
1284 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1285 if (rc < 0) {
1286 return rc;
1287 }
1288
1289 return pldm__msgbuf_insert_array_void(dst, ascii, len);
1290}
1291
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301292__attribute__((always_inline)) static inline int
1293pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1294{
1295 void *utf16 = NULL;
1296 size_t len = 0;
1297 int rc;
1298
1299 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1300 if (rc < 0) {
1301 return rc;
1302 }
1303
1304 return pldm__msgbuf_insert_array_void(dst, utf16, len);
1305}
1306
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301307#ifdef __cplusplus
1308}
1309#endif
1310
Andrew Jeffery66c77232024-04-24 11:42:02 +09301311#ifdef __cplusplus
1312#include <type_traits>
1313
1314template <typename T>
1315static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1316 void *buf)
1317{
1318 static_assert(std::is_same<uint8_t *, T>::value);
1319 return pldm__msgbuf_extract_uint8(ctx, buf);
1320}
1321
1322template <typename T>
1323static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1324 void *buf)
1325{
1326 static_assert(std::is_same<int8_t *, T>::value);
1327 return pldm__msgbuf_extract_int8(ctx, buf);
1328}
1329
1330template <typename T>
1331static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1332 void *buf)
1333{
1334 static_assert(std::is_same<uint16_t *, T>::value);
1335 return pldm__msgbuf_extract_uint16(ctx, buf);
1336}
1337
1338template <typename T>
1339static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1340 void *buf)
1341{
1342 static_assert(std::is_same<int16_t *, T>::value);
1343 return pldm__msgbuf_extract_int16(ctx, buf);
1344}
1345
1346template <typename T>
1347static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1348 void *buf)
1349{
1350 static_assert(std::is_same<uint32_t *, T>::value);
1351 return pldm__msgbuf_extract_uint32(ctx, buf);
1352}
1353
1354template <typename T>
1355static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1356 void *buf)
1357{
1358 static_assert(std::is_same<int32_t *, T>::value);
1359 return pldm__msgbuf_extract_int32(ctx, buf);
1360}
1361
1362template <typename T>
1363static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1364 void *buf)
1365{
1366 static_assert(std::is_same<real32_t *, T>::value);
1367 return pldm__msgbuf_extract_real32(ctx, buf);
1368}
1369#endif
1370
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301371#endif /* BUF_H */