blob: f69c4284b83c644256f0d18b24677c0cad8c2ee9 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10302#ifndef PLDM_MSGBUF_H
3#define PLDM_MSGBUF_H
4
Andrew Jeffery66c77232024-04-24 11:42:02 +09305/*
6 * Historically, many of the structs exposed in libpldm's public headers are
7 * defined with __attribute__((packed)). This is unfortunate: it gives the
8 * impression that a wire-format buffer can be cast to the message type to make
9 * the message's fields easily accessible. As it turns out, that's not
10 * that's valid for several reasons:
11 *
12 * 1. Casting the wire-format buffer to a struct of the message type doesn't
13 * abstract the endianness of message field values
14 *
15 * 2. Some messages contain packed tagged union fields which cannot be properly
16 * described in a C struct.
17 *
18 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
19 * that is type-safe, spatially memory-safe, endian-safe, performant, and
20 * free of undefined-behaviour. Message structs that are added to the public
21 * library API should no-longer be marked __attribute__((packed)), and the
22 * implementation of their encode and decode functions must exploit the msgbuf
23 * API.
24 *
25 * However, we would like to allow implementation of codec functions in terms of
26 * msgbuf APIs even if they're decoding a message into a (historically) packed
27 * struct. Some of the complexity that follows is a consequence of the packed/
28 * unpacked conflict.
29 */
30
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103031#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093032/*
33 * Fix up C11's _Static_assert() vs C++'s static_assert().
34 *
35 * Can we please have nice things for once.
36 */
37// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
38#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103039extern "C" {
40#endif
41
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103042#include <libpldm/base.h>
43#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103044
Andrew Jeffery66c77232024-04-24 11:42:02 +093045#include "compiler.h"
46
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103047#include <assert.h>
48#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093049#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103050#include <limits.h>
51#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093052#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103053#include <string.h>
54#include <sys/types.h>
55
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093056/*
57 * We can't use static_assert() outside of some other C construct. Deal
58 * with high-level global assertions by burying them in an unused struct
59 * declaration, that has a sole member for compliance with the requirement that
60 * types must have a size.
61*/
62static struct {
63 static_assert(
64 INTMAX_MAX != SIZE_MAX,
65 "Extraction and insertion value comparisons may be broken");
66 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
67 "Extraction and insertion arithmetic may be broken");
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093068 static_assert(PLDM_SUCCESS == 0, "Error handling is broken");
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093069 int compliance;
70} build_assertions __attribute__((unused));
71
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093072enum pldm_msgbuf_error_mode {
73 PLDM_MSGBUF_PLDM_CC = 0x5a,
74 PLDM_MSGBUF_C_ERRNO = 0xa5,
75};
76
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103077struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070078 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093079 intmax_t remaining;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093080 enum pldm_msgbuf_error_mode mode;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103081};
82
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093083__attribute__((always_inline)) static inline int
84pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err)
85{
86 int rc;
87
88 assert(err != 0);
89 assert(err <= INT_MAX);
90
91 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
92 if (err > INT_MAX) {
93 return -EINVAL;
94 }
95
96 static_assert(INT_MIN + INT_MAX < 0,
97 "Arithmetic assumption failure");
98 return -((int)err);
99 }
100
101 if (err > INT_MAX) {
102 return PLDM_ERROR;
103 }
104
105 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
106 switch (err) {
107 case EINVAL:
108 rc = PLDM_ERROR_INVALID_DATA;
109 break;
110 case EBADMSG:
111 case EOVERFLOW:
112 rc = PLDM_ERROR_INVALID_LENGTH;
113 break;
114 default:
115 assert(false);
116 rc = PLDM_ERROR;
117 break;
118 }
119
120 assert(rc > 0);
121 return rc;
122}
123
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030124/**
125 * @brief Initialize pldm buf struct for buf extractor
126 *
127 * @param[out] ctx - pldm_msgbuf context for extractor
128 * @param[in] minsize - The minimum required length of buffer `buf`
129 * @param[in] buf - buffer to be extracted
130 * @param[in] len - size of buffer
131 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930132 * @return 0 on success, otherwise an error code appropriate for the current
133 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030134 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930135__attribute__((always_inline)) static inline int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930136// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
137pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
138 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030139{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930140 assert(ctx);
141 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
142 ctx->mode == PLDM_MSGBUF_C_ERRNO);
143
144 if (!buf) {
145 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030146 }
147
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930148 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930149 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030150 }
151
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930152#if INTMAX_MAX < SIZE_MAX
153 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930154 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930155 }
156#endif
157
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930158 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930159 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030160 }
161
162 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930163 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030164
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930165 return 0;
166}
167
168/**
169 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
170 *
171 * @see pldm__msgbuf_init
172 *
173 * @param[out] ctx - pldm_msgbuf context for extractor
174 * @param[in] minsize - The minimum required length of buffer `buf`
175 * @param[in] buf - buffer to be extracted
176 * @param[in] len - size of buffer
177 *
178 * @return PLDM_SUCCESS if the provided buffer region is sensible,
179 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
180 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
181 */
182__attribute__((always_inline)) static inline int
183pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
184 size_t len)
185{
186 if (!ctx) {
187 return PLDM_ERROR_INVALID_DATA;
188 }
189
190 ctx->mode = PLDM_MSGBUF_PLDM_CC;
191 return pldm__msgbuf_init(ctx, minsize, buf, len);
192}
193
194/**
195 * @brief Initialise a msgbuf instance to return errors as negative errno values
196 *
197 * @see pldm__msgbuf_init
198 *
199 * @param[out] ctx - pldm_msgbuf context for extractor
200 * @param[in] minsize - The minimum required length of buffer `buf`
201 * @param[in] buf - buffer to be extracted
202 * @param[in] len - size of buffer
203 *
204 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
205 * pointer parameters are invalid, or -EOVERFLOW if length constraints
206 * are violated.
207 */
208__attribute__((always_inline)) static inline int
209pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
210 size_t len)
211{
212 if (!ctx) {
213 return -EINVAL;
214 }
215
216 ctx->mode = PLDM_MSGBUF_C_ERRNO;
217 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030218}
219
220/**
221 * @brief Validate buffer overflow state
222 *
223 * @param[in] ctx - pldm_msgbuf context for extractor
224 *
225 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
226 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
227 * prior accesses would have occurred beyond the bounds of the buffer, and
228 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
229 * pointer.
230 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930231__attribute__((always_inline)) static inline int
232pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030233{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930234 assert(ctx);
235 if (ctx->remaining < 0) {
236 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030237 }
238
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930239 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030240}
241
242/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930243 * @brief Test whether a message buffer has been exactly consumed
244 *
245 * @param[in] ctx - pldm_msgbuf context for extractor
246 *
247 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
248 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
249 * indicates that an incorrect sequence of accesses have occurred, and
250 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
251 * pointer.
252 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930253__attribute__((always_inline)) static inline int
254pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930255{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930256 assert(ctx);
257 if (ctx->remaining != 0) {
258 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930259 }
260
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930261 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930262}
263
264/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030265 * @brief Destroy the pldm buf
266 *
267 * @param[in] ctx - pldm_msgbuf context for extractor
268 *
269 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
270 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
271 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
272 * bounds of the buffer.
273 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930274__attribute__((always_inline)) static inline int
275pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030276{
277 int valid;
278
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930279 assert(ctx);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030280 valid = pldm_msgbuf_validate(ctx);
281
282 ctx->cursor = NULL;
283 ctx->remaining = 0;
284
285 return valid;
286}
287
288/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930289 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
290 * has been completely consumed without overflow
291 *
292 * @param[in] ctx - pldm_msgbuf context
293 *
294 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
295 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
296 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
297 * have occurred byond the bounds of the buffer
298 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930299__attribute__((always_inline)) static inline int
300pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930301{
302 int consumed;
303
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930304 assert(ctx);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930305 consumed = pldm_msgbuf_consumed(ctx);
306
307 ctx->cursor = NULL;
308 ctx->remaining = 0;
309
310 return consumed;
311}
312
Andrew Jeffery66c77232024-04-24 11:42:02 +0930313/*
314 * Exploit the pre-processor to perform type checking by macro substitution.
315 *
316 * A C type is defined by its alignment as well as its object
317 * size, and compilers have a hammer to enforce it in the form of
318 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
319 * the libpldm public API this presents a problem: Naively attempting to use the
320 * msgbuf APIs on a member of a packed struct would yield an error.
321 *
322 * The msgbuf APIs are implemented such that data is moved through unaligned
323 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
324 * make the object pointers take a trip through `void *` at its API boundary.
325 * That presents a bit too much of an opportunity to non-surgically remove your
326 * own foot, so here we set about doing something to mitigate that as well.
327 *
328 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
329 * only for the purpose of object sizes, disregarding alignment. We have a few
330 * constraints that cause some headaches:
331 *
332 * 1. We have to perform the type-check before a call through a C function,
333 * as the function must take the object pointer argument as `void *`.
334 * Essentially, this constrains us to doing something with macros.
335 *
336 * 2. While libpldm is a C library, its test suite is written in C++ to take
337 * advantage of gtest.
338 *
339 * 3. Ideally we'd do something with C's `static_assert()`, however
340 * `static_assert()` is defined as void, and as we're constrained to macros,
341 * using `static_assert()` would require a statement-expression
342 *
343 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
344 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
345 * the purpose of enabling statement-expressions in this one instance.
346 *
347 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
348 * however it's implemented in terms of `_Generic()`, which is not available
349 * in C++.
350 *
351 * Combined this means we need separate solutions for C and C++.
352 *
353 * For C, as we don't have statement-expressions, we need to exploit some other
354 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
355 * API function call. We also have to take care of the fact that the call-sites
356 * may be in the context of a variable assignment for error-handling purposes.
357 * The key observation is that we can use the comma operator as a sequence point
358 * to order the type check before the API call, discarding the "result" value of
359 * the type check and yielding the return value of the API call.
360 *
361 * C++ could be less of a headache than the C as we can leverage template
362 * functions. An advantage of template functions is that while their definition
363 * is driven by instantion, the definition does not appear at the source
364 * location of the instantation, which gives it a great leg-up over the problems
365 * we have in the C path. However, the use of the msgbuf APIs in the test suite
366 * still makes things somewhat tricky, as the call-sites in the test suite are
367 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
368 * takes both the object type and the required type as template arguments, and
369 * then define the object pointer parameter as `void *` for a call through to
370 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
371 * encapsulated in gtest macros, use of commas in the template specification
372 * causes pre-processor confusion. In this way we're constrained to only one
373 * template argument per function.
374 *
375 * Implement the C++ path using template functions that take the destination
376 * object type as a template argument, while the name of the function symbols
377 * are derived from the required type. The manual implementations of these
378 * appear at the end of the header. The type safety is actually enforced
379 * by `static_assert()` this time, as we can use statements as we're not
380 * constrained to an expression in the templated function body.
381 *
382 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
383 * double-evaluation of some arguments. We're not yet bothered by this for two
384 * reasons:
385 *
386 * 1. The nature of the current call-sites are such that there are no
387 * argument expressions that result in undesirable side-effects
388 *
389 * 2. It's an API internal to the libpldm implementation, and we can fix things
390 * whenever something crops up the violates the observation in 1.
391 */
392#ifdef __cplusplus
393#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
394 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
395#else
396#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
397 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
398#endif
399
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930400/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030401 * @brief pldm_msgbuf extractor for a uint8_t
402 *
403 * @param[inout] ctx - pldm_msgbuf context for extractor
404 * @param[out] dst - destination of extracted value
405 *
406 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
407 * PLDM_ERROR_INVALID_LENGTH otherwise.
408 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
409 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930410#define pldm_msgbuf_extract_uint8(ctx, dst) \
411 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
412 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930413__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930414// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930415pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030416{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930417 assert(ctx);
418
419 if (!ctx->cursor || !dst) {
420 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030421 }
422
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930423 if (ctx->remaining == INTMAX_MIN) {
424 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930425 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930426 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930427 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030428 assert(ctx->remaining >= 0);
429 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930430 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030431 }
432
Andrew Jeffery66c77232024-04-24 11:42:02 +0930433 memcpy(dst, ctx->cursor, sizeof(uint8_t));
434
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030435 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930436 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030437}
438
Andrew Jeffery66c77232024-04-24 11:42:02 +0930439#define pldm_msgbuf_extract_int8(ctx, dst) \
440 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
441 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930442__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930443// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930444pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030445{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930446 assert(ctx);
447
448 if (!ctx->cursor || !dst) {
449 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030450 }
451
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930452 if (ctx->remaining == INTMAX_MIN) {
453 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930454 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930455 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930456 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030457 assert(ctx->remaining >= 0);
458 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930459 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030460 }
461
Andrew Jeffery66c77232024-04-24 11:42:02 +0930462 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030463 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930464 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030465}
466
Andrew Jeffery66c77232024-04-24 11:42:02 +0930467#define pldm_msgbuf_extract_uint16(ctx, dst) \
468 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
469 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930470__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930471// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930472pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030473{
474 uint16_t ldst;
475
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930476 assert(ctx);
477
478 if (!ctx->cursor || !dst) {
479 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030480 }
481
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930482 // Check for underflow while tracking the magnitude of the buffer overflow
483 static_assert(
484 // NOLINTNEXTLINE(bugprone-sizeof-expression)
485 sizeof(ldst) < INTMAX_MAX,
486 "The following addition may not uphold the runtime assertion");
487 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
488 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930489 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930490 }
491
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030492 // Check for buffer overflow. If we overflow, account for the request as
493 // negative values in ctx->remaining. This way we can debug how far
494 // we've overflowed.
495 ctx->remaining -= sizeof(ldst);
496
497 // Prevent the access if it would overflow. First, assert so we blow up
498 // the test suite right at the point of failure. However, cater to
499 // -DNDEBUG by explicitly testing that the access is valid.
500 assert(ctx->remaining >= 0);
501 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930502 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030503 }
504
505 // Use memcpy() to have the compiler deal with any alignment
506 // issues on the target architecture
507 memcpy(&ldst, ctx->cursor, sizeof(ldst));
508
509 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930510 ldst = le16toh(ldst);
511
512 // Allow storing to unaligned
513 memcpy(dst, &ldst, sizeof(ldst));
514
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030515 ctx->cursor += sizeof(ldst);
516
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930517 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030518}
519
Andrew Jeffery66c77232024-04-24 11:42:02 +0930520#define pldm_msgbuf_extract_int16(ctx, dst) \
521 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
522 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930523__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930524// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930525pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030526{
527 int16_t ldst;
528
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930529 assert(ctx);
530
531 if (!ctx->cursor || !dst) {
532 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030533 }
534
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930535 static_assert(
536 // NOLINTNEXTLINE(bugprone-sizeof-expression)
537 sizeof(ldst) < INTMAX_MAX,
538 "The following addition may not uphold the runtime assertion");
539 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
540 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930541 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930542 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030543 ctx->remaining -= sizeof(ldst);
544 assert(ctx->remaining >= 0);
545 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930546 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030547 }
548
549 memcpy(&ldst, ctx->cursor, sizeof(ldst));
550
Andrew Jeffery66c77232024-04-24 11:42:02 +0930551 ldst = le16toh(ldst);
552 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030553 ctx->cursor += sizeof(ldst);
554
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930555 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030556}
557
Andrew Jeffery66c77232024-04-24 11:42:02 +0930558#define pldm_msgbuf_extract_uint32(ctx, dst) \
559 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
560 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930561__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930562// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930563pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030564{
565 uint32_t ldst;
566
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930567 assert(ctx);
568
569 if (!ctx->cursor || !dst) {
570 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030571 }
572
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930573 static_assert(
574 // NOLINTNEXTLINE(bugprone-sizeof-expression)
575 sizeof(ldst) < INTMAX_MAX,
576 "The following addition may not uphold the runtime assertion");
577 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
578 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930579 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930580 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030581 ctx->remaining -= sizeof(ldst);
582 assert(ctx->remaining >= 0);
583 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930584 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030585 }
586
587 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930588 ldst = le32toh(ldst);
589 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030590 ctx->cursor += sizeof(ldst);
591
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930592 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030593}
594
Andrew Jeffery66c77232024-04-24 11:42:02 +0930595#define pldm_msgbuf_extract_int32(ctx, dst) \
596 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
597 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930598__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930599// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930600pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030601{
602 int32_t ldst;
603
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930604 assert(ctx);
605
606 if (!ctx->cursor || !dst) {
607 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030608 }
609
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930610 static_assert(
611 // NOLINTNEXTLINE(bugprone-sizeof-expression)
612 sizeof(ldst) < INTMAX_MAX,
613 "The following addition may not uphold the runtime assertion");
614 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
615 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930616 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930617 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030618 ctx->remaining -= sizeof(ldst);
619 assert(ctx->remaining >= 0);
620 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930621 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030622 }
623
624 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930625 ldst = le32toh(ldst);
626 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030627 ctx->cursor += sizeof(ldst);
628
629 return PLDM_SUCCESS;
630}
631
Andrew Jeffery66c77232024-04-24 11:42:02 +0930632#define pldm_msgbuf_extract_real32(ctx, dst) \
633 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
634 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930635__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930636// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930637pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030638{
639 uint32_t ldst;
640
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930641 static_assert(sizeof(real32_t) == sizeof(ldst),
642 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930643
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930644 assert(ctx);
645
646 if (!ctx->cursor || !dst) {
647 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030648 }
649
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930650 static_assert(
651 // NOLINTNEXTLINE(bugprone-sizeof-expression)
652 sizeof(ldst) < INTMAX_MAX,
653 "The following addition may not uphold the runtime assertion");
654 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
655 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930656 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930657 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030658 ctx->remaining -= sizeof(ldst);
659 assert(ctx->remaining >= 0);
660 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930661 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030662 }
663
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030664 memcpy(&ldst, ctx->cursor, sizeof(ldst));
665 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930666 memcpy(dst, &ldst, sizeof(ldst));
667 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030668
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930669 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030670}
671
Andrew Jeffery66c77232024-04-24 11:42:02 +0930672/**
673 * Extract the field at the msgbuf cursor into the lvalue named by dst.
674 *
675 * @param ctx The msgbuf context object
676 * @param dst The lvalue into which the field at the msgbuf cursor should be
677 * extracted
678 *
679 * @return PLDM_SUCCESS on success, otherwise another value on error
680 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030681#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930682 _Generic((dst), \
683 uint8_t: pldm__msgbuf_extract_uint8, \
684 int8_t: pldm__msgbuf_extract_int8, \
685 uint16_t: pldm__msgbuf_extract_uint16, \
686 int16_t: pldm__msgbuf_extract_int16, \
687 uint32_t: pldm__msgbuf_extract_uint32, \
688 int32_t: pldm__msgbuf_extract_int32, \
689 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
690
691/**
692 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
693 *
694 * @param ctx The msgbuf context object
695 * @param dst The pointer to the object into which the field at the msgbuf
696 * cursor should be extracted
697 *
698 * @return PLDM_SUCCESS on success, otherwise another value on error
699 */
700#define pldm_msgbuf_extract_p(ctx, dst) \
701 _Generic((dst), \
702 uint8_t *: pldm__msgbuf_extract_uint8, \
703 int8_t *: pldm__msgbuf_extract_int8, \
704 uint16_t *: pldm__msgbuf_extract_uint16, \
705 int16_t *: pldm__msgbuf_extract_int16, \
706 uint32_t *: pldm__msgbuf_extract_uint32, \
707 int32_t *: pldm__msgbuf_extract_int32, \
708 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030709
Andrew Jeffery76712f62024-05-22 15:19:00 +0930710__attribute__((always_inline)) static inline int
711pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
712 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930713{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930714 assert(ctx);
715
716 if (!ctx->cursor || !dst) {
717 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930718 }
719
720 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930721 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930722 }
723
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930724#if INTMAX_MAX < SIZE_MAX
725 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930726 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930727 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930728#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930729
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930730 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930731 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930732 }
733 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930734 assert(ctx->remaining >= 0);
735 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930736 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930737 }
738
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030739 memcpy(dst, ctx->cursor, count);
740 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930741
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930742 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930743}
744
745#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930746 _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
747 count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930748
Andrew Jeffery76712f62024-05-22 15:19:00 +0930749__attribute__((always_inline)) static inline int
750pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700751{
752 uint32_t val = htole32(src);
753
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930754 assert(ctx);
755
756 if (!ctx->cursor) {
757 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700758 }
759
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930760 static_assert(
761 // NOLINTNEXTLINE(bugprone-sizeof-expression)
762 sizeof(src) < INTMAX_MAX,
763 "The following addition may not uphold the runtime assertion");
764 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
765 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930766 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930767 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700768 ctx->remaining -= sizeof(src);
769 assert(ctx->remaining >= 0);
770 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930771 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700772 }
773
774 memcpy(ctx->cursor, &val, sizeof(val));
775 ctx->cursor += sizeof(src);
776
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930777 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700778}
779
Andrew Jeffery76712f62024-05-22 15:19:00 +0930780__attribute__((always_inline)) static inline int
781pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700782{
783 uint16_t val = htole16(src);
784
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930785 assert(ctx);
786
787 if (!ctx->cursor) {
788 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700789 }
790
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930791 static_assert(
792 // NOLINTNEXTLINE(bugprone-sizeof-expression)
793 sizeof(src) < INTMAX_MAX,
794 "The following addition may not uphold the runtime assertion");
795 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
796 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930797 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930798 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700799 ctx->remaining -= sizeof(src);
800 assert(ctx->remaining >= 0);
801 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930802 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700803 }
804
805 memcpy(ctx->cursor, &val, sizeof(val));
806 ctx->cursor += sizeof(src);
807
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930808 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700809}
810
Andrew Jeffery76712f62024-05-22 15:19:00 +0930811__attribute__((always_inline)) static inline int
812pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700813{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930814 assert(ctx);
815
816 if (!ctx->cursor) {
817 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700818 }
819
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930820 static_assert(
821 // NOLINTNEXTLINE(bugprone-sizeof-expression)
822 sizeof(src) < INTMAX_MAX,
823 "The following addition may not uphold the runtime assertion");
824 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
825 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930826 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930827 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700828 ctx->remaining -= sizeof(src);
829 assert(ctx->remaining >= 0);
830 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930831 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700832 }
833
834 memcpy(ctx->cursor, &src, sizeof(src));
835 ctx->cursor += sizeof(src);
836
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930837 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700838}
839
Andrew Jeffery76712f62024-05-22 15:19:00 +0930840__attribute__((always_inline)) static inline int
841pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700842{
843 int32_t val = htole32(src);
844
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930845 assert(ctx);
846
847 if (!ctx->cursor) {
848 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700849 }
850
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930851 static_assert(
852 // NOLINTNEXTLINE(bugprone-sizeof-expression)
853 sizeof(src) < INTMAX_MAX,
854 "The following addition may not uphold the runtime assertion");
855 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
856 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930857 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930858 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700859 ctx->remaining -= sizeof(src);
860 assert(ctx->remaining >= 0);
861 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930862 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700863 }
864
865 memcpy(ctx->cursor, &val, sizeof(val));
866 ctx->cursor += sizeof(src);
867
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930868 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700869}
870
Andrew Jeffery76712f62024-05-22 15:19:00 +0930871__attribute__((always_inline)) static inline int
872pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700873{
874 int16_t val = htole16(src);
875
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930876 assert(ctx);
877
878 if (!ctx->cursor) {
879 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700880 }
881
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930882 static_assert(
883 // NOLINTNEXTLINE(bugprone-sizeof-expression)
884 sizeof(src) < INTMAX_MAX,
885 "The following addition may not uphold the runtime assertion");
886 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
887 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930888 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930889 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700890 ctx->remaining -= sizeof(src);
891 assert(ctx->remaining >= 0);
892 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930893 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700894 }
895
896 memcpy(ctx->cursor, &val, sizeof(val));
897 ctx->cursor += sizeof(src);
898
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930899 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700900}
901
Andrew Jeffery76712f62024-05-22 15:19:00 +0930902__attribute__((always_inline)) static inline int
903pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700904{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930905 assert(ctx);
906
907 if (!ctx->cursor) {
908 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700909 }
910
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930911 static_assert(
912 // NOLINTNEXTLINE(bugprone-sizeof-expression)
913 sizeof(src) < INTMAX_MAX,
914 "The following addition may not uphold the runtime assertion");
915 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
916 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930917 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930918 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700919 ctx->remaining -= sizeof(src);
920 assert(ctx->remaining >= 0);
921 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930922 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700923 }
924
925 memcpy(ctx->cursor, &src, sizeof(src));
926 ctx->cursor += sizeof(src);
927
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930928 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700929}
930
931#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930932 _Generic((src), \
933 uint8_t: pldm_msgbuf_insert_uint8, \
934 int8_t: pldm_msgbuf_insert_int8, \
935 uint16_t: pldm_msgbuf_insert_uint16, \
936 int16_t: pldm_msgbuf_insert_int16, \
937 uint32_t: pldm_msgbuf_insert_uint32, \
938 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700939
Andrew Jeffery76712f62024-05-22 15:19:00 +0930940__attribute__((always_inline)) static inline int
941pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
942 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700943{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930944 assert(ctx);
945
946 if (!ctx->cursor || !src) {
947 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700948 }
949
950 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930951 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700952 }
953
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930954#if INTMAX_MAX < SIZE_MAX
955 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930956 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700957 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930958#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700959
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930960 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930961 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930962 }
963 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700964 assert(ctx->remaining >= 0);
965 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930966 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700967 }
968
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030969 memcpy(ctx->cursor, src, count);
970 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700971
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930972 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700973}
974
975#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930976 _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \
977 count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700978
Andrew Jeffery76712f62024-05-22 15:19:00 +0930979__attribute__((always_inline)) static inline int
980pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
981 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700982{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930983 assert(ctx);
984
985 if (!ctx->cursor || !cursor || *cursor) {
986 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700987 }
988
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930989#if INTMAX_MAX < SIZE_MAX
990 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930991 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700992 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930993#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700994
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930995 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930996 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930997 }
998 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +0700999 assert(ctx->remaining >= 0);
1000 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301001 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001002 }
1003
1004 *cursor = ctx->cursor;
1005 ctx->cursor += required;
1006
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301007 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001008}
1009
Andrew Jeffery76712f62024-05-22 15:19:00 +09301010__attribute__((always_inline)) static inline int
1011pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001012{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301013 assert(ctx);
1014
1015 if (!ctx->cursor || !cursor || *cursor || !len) {
1016 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001017 }
1018
1019 assert(ctx->remaining >= 0);
1020 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301021 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001022 }
1023
1024 *cursor = ctx->cursor;
1025 ctx->cursor += ctx->remaining;
1026 *len = ctx->remaining;
1027 ctx->remaining = 0;
1028
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301029 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001030}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001031
1032/**
1033 * @brief pldm_msgbuf copy data between two msg buffers
1034 *
1035 * @param[inout] src - pldm_msgbuf for source from where value should be copied
1036 * @param[inout] dst - destination of copy from source
1037 * @param[in] size - size of data to be copied
1038 * @param[in] description - description of data copied
1039 *
1040 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1041 * PLDM_ERROR_INVALID_LENGTH otherwise.
1042 * PLDM_ERROR_INVALID_DATA if input is invalid
1043 */
1044#define pldm_msgbuf_copy(dst, src, type, name) \
1045 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301046__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001047// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301048pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
1049 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001050{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301051 assert(src);
1052 assert(dst);
1053 assert(src->mode == dst->mode);
1054
1055 if (!src->cursor || !dst->cursor || !description) {
1056 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001057 }
1058
1059#if INTMAX_MAX < SIZE_MAX
1060 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301061 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001062 }
1063#endif
1064
1065 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301066 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001067 }
1068
1069 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301070 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001071 }
1072
1073 src->remaining -= (intmax_t)size;
1074 assert(src->remaining >= 0);
1075 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301076 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001077 }
1078
1079 dst->remaining -= (intmax_t)size;
1080 assert(dst->remaining >= 0);
1081 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301082 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001083 }
1084
1085 memcpy(dst->cursor, src->cursor, size);
1086 src->cursor += size;
1087 dst->cursor += size;
1088
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301089 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001090}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301091
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301092#ifdef __cplusplus
1093}
1094#endif
1095
Andrew Jeffery66c77232024-04-24 11:42:02 +09301096#ifdef __cplusplus
1097#include <type_traits>
1098
1099template <typename T>
1100static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1101 void *buf)
1102{
1103 static_assert(std::is_same<uint8_t *, T>::value);
1104 return pldm__msgbuf_extract_uint8(ctx, buf);
1105}
1106
1107template <typename T>
1108static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1109 void *buf)
1110{
1111 static_assert(std::is_same<int8_t *, T>::value);
1112 return pldm__msgbuf_extract_int8(ctx, buf);
1113}
1114
1115template <typename T>
1116static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1117 void *buf)
1118{
1119 static_assert(std::is_same<uint16_t *, T>::value);
1120 return pldm__msgbuf_extract_uint16(ctx, buf);
1121}
1122
1123template <typename T>
1124static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1125 void *buf)
1126{
1127 static_assert(std::is_same<int16_t *, T>::value);
1128 return pldm__msgbuf_extract_int16(ctx, buf);
1129}
1130
1131template <typename T>
1132static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1133 void *buf)
1134{
1135 static_assert(std::is_same<uint32_t *, T>::value);
1136 return pldm__msgbuf_extract_uint32(ctx, buf);
1137}
1138
1139template <typename T>
1140static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1141 void *buf)
1142{
1143 static_assert(std::is_same<int32_t *, T>::value);
1144 return pldm__msgbuf_extract_int32(ctx, buf);
1145}
1146
1147template <typename T>
1148static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1149 void *buf)
1150{
1151 static_assert(std::is_same<real32_t *, T>::value);
1152 return pldm__msgbuf_extract_real32(ctx, buf);
1153}
1154#endif
1155
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301156#endif /* BUF_H */