blob: e5e91ed9674df1dd071c8771b85b456705413124 [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 Jefferyd861a682024-06-03 21:43:09 +093083/**
84 * @brief Either negate an errno value or return a value mapped to a PLDM
85 * completion code.
86 *
87 * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API
88 * for ergonomics. It's preferred that we don't try to unify this with
89 * `pldm_xlate_errno()` from src/api.h despite the similarities.
90 *
91 * @param[in] ctx - The msgbuf context providing the personality info
92 * @param[in] err - The positive errno value to translate
93 *
94 * @return Either the negated value of @p err if the context's error mode is
95 * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the
96 * error mode is `PLDM_MSGBUF_PLDM_CC`.
97 */
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093098__attribute__((always_inline)) static inline int
99pldm_msgbuf_status(struct pldm_msgbuf *ctx, unsigned int err)
100{
101 int rc;
102
103 assert(err != 0);
104 assert(err <= INT_MAX);
105
106 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
107 if (err > INT_MAX) {
108 return -EINVAL;
109 }
110
111 static_assert(INT_MIN + INT_MAX < 0,
112 "Arithmetic assumption failure");
113 return -((int)err);
114 }
115
116 if (err > INT_MAX) {
117 return PLDM_ERROR;
118 }
119
120 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
121 switch (err) {
122 case EINVAL:
123 rc = PLDM_ERROR_INVALID_DATA;
124 break;
125 case EBADMSG:
126 case EOVERFLOW:
127 rc = PLDM_ERROR_INVALID_LENGTH;
128 break;
129 default:
130 assert(false);
131 rc = PLDM_ERROR;
132 break;
133 }
134
135 assert(rc > 0);
136 return rc;
137}
138
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030139/**
140 * @brief Initialize pldm buf struct for buf extractor
141 *
142 * @param[out] ctx - pldm_msgbuf context for extractor
143 * @param[in] minsize - The minimum required length of buffer `buf`
144 * @param[in] buf - buffer to be extracted
145 * @param[in] len - size of buffer
146 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930147 * @return 0 on success, otherwise an error code appropriate for the current
148 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030149 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930150__attribute__((always_inline)) static inline int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930151// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
152pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
153 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030154{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930155 assert(ctx);
156 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
157 ctx->mode == PLDM_MSGBUF_C_ERRNO);
158
159 if (!buf) {
160 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030161 }
162
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930163 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930164 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030165 }
166
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930167#if INTMAX_MAX < SIZE_MAX
168 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930169 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930170 }
171#endif
172
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930173 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930174 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030175 }
176
177 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930178 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030179
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930180 return 0;
181}
182
183/**
184 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
185 *
186 * @see pldm__msgbuf_init
187 *
188 * @param[out] ctx - pldm_msgbuf context for extractor
189 * @param[in] minsize - The minimum required length of buffer `buf`
190 * @param[in] buf - buffer to be extracted
191 * @param[in] len - size of buffer
192 *
193 * @return PLDM_SUCCESS if the provided buffer region is sensible,
194 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
195 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
196 */
197__attribute__((always_inline)) static inline int
198pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
199 size_t len)
200{
201 if (!ctx) {
202 return PLDM_ERROR_INVALID_DATA;
203 }
204
205 ctx->mode = PLDM_MSGBUF_PLDM_CC;
206 return pldm__msgbuf_init(ctx, minsize, buf, len);
207}
208
209/**
210 * @brief Initialise a msgbuf instance to return errors as negative errno values
211 *
212 * @see pldm__msgbuf_init
213 *
214 * @param[out] ctx - pldm_msgbuf context for extractor
215 * @param[in] minsize - The minimum required length of buffer `buf`
216 * @param[in] buf - buffer to be extracted
217 * @param[in] len - size of buffer
218 *
219 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
220 * pointer parameters are invalid, or -EOVERFLOW if length constraints
221 * are violated.
222 */
223__attribute__((always_inline)) static inline int
224pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
225 size_t len)
226{
227 if (!ctx) {
228 return -EINVAL;
229 }
230
231 ctx->mode = PLDM_MSGBUF_C_ERRNO;
232 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030233}
234
235/**
236 * @brief Validate buffer overflow state
237 *
238 * @param[in] ctx - pldm_msgbuf context for extractor
239 *
240 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
241 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
242 * prior accesses would have occurred beyond the bounds of the buffer, and
243 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
244 * pointer.
245 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930246__attribute__((always_inline)) static inline int
247pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030248{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930249 assert(ctx);
250 if (ctx->remaining < 0) {
251 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030252 }
253
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930254 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030255}
256
257/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930258 * @brief Test whether a message buffer has been exactly consumed
259 *
260 * @param[in] ctx - pldm_msgbuf context for extractor
261 *
262 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
263 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
264 * indicates that an incorrect sequence of accesses have occurred, and
265 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
266 * pointer.
267 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930268__attribute__((always_inline)) static inline int
269pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930270{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930271 assert(ctx);
272 if (ctx->remaining != 0) {
273 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930274 }
275
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930276 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930277}
278
279/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030280 * @brief Destroy the pldm buf
281 *
282 * @param[in] ctx - pldm_msgbuf context for extractor
283 *
284 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
285 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
286 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
287 * bounds of the buffer.
288 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930289__attribute__((always_inline)) static inline int
290pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030291{
292 int valid;
293
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930294 assert(ctx);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030295 valid = pldm_msgbuf_validate(ctx);
296
297 ctx->cursor = NULL;
298 ctx->remaining = 0;
299
300 return valid;
301}
302
303/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930304 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
305 * has been completely consumed without overflow
306 *
307 * @param[in] ctx - pldm_msgbuf context
308 *
309 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
310 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
311 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
312 * have occurred byond the bounds of the buffer
313 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930314__attribute__((always_inline)) static inline int
315pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930316{
317 int consumed;
318
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930319 assert(ctx);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930320 consumed = pldm_msgbuf_consumed(ctx);
321
322 ctx->cursor = NULL;
323 ctx->remaining = 0;
324
325 return consumed;
326}
327
Andrew Jeffery66c77232024-04-24 11:42:02 +0930328/*
329 * Exploit the pre-processor to perform type checking by macro substitution.
330 *
331 * A C type is defined by its alignment as well as its object
332 * size, and compilers have a hammer to enforce it in the form of
333 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
334 * the libpldm public API this presents a problem: Naively attempting to use the
335 * msgbuf APIs on a member of a packed struct would yield an error.
336 *
337 * The msgbuf APIs are implemented such that data is moved through unaligned
338 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
339 * make the object pointers take a trip through `void *` at its API boundary.
340 * That presents a bit too much of an opportunity to non-surgically remove your
341 * own foot, so here we set about doing something to mitigate that as well.
342 *
343 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
344 * only for the purpose of object sizes, disregarding alignment. We have a few
345 * constraints that cause some headaches:
346 *
347 * 1. We have to perform the type-check before a call through a C function,
348 * as the function must take the object pointer argument as `void *`.
349 * Essentially, this constrains us to doing something with macros.
350 *
351 * 2. While libpldm is a C library, its test suite is written in C++ to take
352 * advantage of gtest.
353 *
354 * 3. Ideally we'd do something with C's `static_assert()`, however
355 * `static_assert()` is defined as void, and as we're constrained to macros,
356 * using `static_assert()` would require a statement-expression
357 *
358 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
359 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
360 * the purpose of enabling statement-expressions in this one instance.
361 *
362 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
363 * however it's implemented in terms of `_Generic()`, which is not available
364 * in C++.
365 *
366 * Combined this means we need separate solutions for C and C++.
367 *
368 * For C, as we don't have statement-expressions, we need to exploit some other
369 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
370 * API function call. We also have to take care of the fact that the call-sites
371 * may be in the context of a variable assignment for error-handling purposes.
372 * The key observation is that we can use the comma operator as a sequence point
373 * to order the type check before the API call, discarding the "result" value of
374 * the type check and yielding the return value of the API call.
375 *
376 * C++ could be less of a headache than the C as we can leverage template
377 * functions. An advantage of template functions is that while their definition
378 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530379 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930380 * we have in the C path. However, the use of the msgbuf APIs in the test suite
381 * still makes things somewhat tricky, as the call-sites in the test suite are
382 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
383 * takes both the object type and the required type as template arguments, and
384 * then define the object pointer parameter as `void *` for a call through to
385 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
386 * encapsulated in gtest macros, use of commas in the template specification
387 * causes pre-processor confusion. In this way we're constrained to only one
388 * template argument per function.
389 *
390 * Implement the C++ path using template functions that take the destination
391 * object type as a template argument, while the name of the function symbols
392 * are derived from the required type. The manual implementations of these
393 * appear at the end of the header. The type safety is actually enforced
394 * by `static_assert()` this time, as we can use statements as we're not
395 * constrained to an expression in the templated function body.
396 *
397 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
398 * double-evaluation of some arguments. We're not yet bothered by this for two
399 * reasons:
400 *
401 * 1. The nature of the current call-sites are such that there are no
402 * argument expressions that result in undesirable side-effects
403 *
404 * 2. It's an API internal to the libpldm implementation, and we can fix things
405 * whenever something crops up the violates the observation in 1.
406 */
407#ifdef __cplusplus
408#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
409 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
410#else
411#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
412 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
413#endif
414
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930415/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030416 * @brief pldm_msgbuf extractor for a uint8_t
417 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530418 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030419 * @param[out] dst - destination of extracted value
420 *
421 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
422 * PLDM_ERROR_INVALID_LENGTH otherwise.
423 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
424 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930425#define pldm_msgbuf_extract_uint8(ctx, dst) \
426 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
427 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930428__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930429// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930430pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030431{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930432 assert(ctx);
433
434 if (!ctx->cursor || !dst) {
435 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030436 }
437
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930438 if (ctx->remaining == INTMAX_MIN) {
439 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930440 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930441 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930442 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030443 assert(ctx->remaining >= 0);
444 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930445 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030446 }
447
Andrew Jeffery66c77232024-04-24 11:42:02 +0930448 memcpy(dst, ctx->cursor, sizeof(uint8_t));
449
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030450 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930451 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030452}
453
Andrew Jeffery66c77232024-04-24 11:42:02 +0930454#define pldm_msgbuf_extract_int8(ctx, dst) \
455 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
456 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930457__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930458// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930459pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030460{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930461 assert(ctx);
462
463 if (!ctx->cursor || !dst) {
464 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030465 }
466
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930467 if (ctx->remaining == INTMAX_MIN) {
468 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930469 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930470 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930471 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030472 assert(ctx->remaining >= 0);
473 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930474 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030475 }
476
Andrew Jeffery66c77232024-04-24 11:42:02 +0930477 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030478 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930479 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030480}
481
Andrew Jeffery66c77232024-04-24 11:42:02 +0930482#define pldm_msgbuf_extract_uint16(ctx, dst) \
483 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
484 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930485__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930486// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930487pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030488{
489 uint16_t ldst;
490
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930491 assert(ctx);
492
493 if (!ctx->cursor || !dst) {
494 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030495 }
496
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930497 // Check for underflow while tracking the magnitude of the buffer overflow
498 static_assert(
499 // NOLINTNEXTLINE(bugprone-sizeof-expression)
500 sizeof(ldst) < INTMAX_MAX,
501 "The following addition may not uphold the runtime assertion");
502 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
503 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930504 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930505 }
506
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030507 // Check for buffer overflow. If we overflow, account for the request as
508 // negative values in ctx->remaining. This way we can debug how far
509 // we've overflowed.
510 ctx->remaining -= sizeof(ldst);
511
512 // Prevent the access if it would overflow. First, assert so we blow up
513 // the test suite right at the point of failure. However, cater to
514 // -DNDEBUG by explicitly testing that the access is valid.
515 assert(ctx->remaining >= 0);
516 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930517 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030518 }
519
520 // Use memcpy() to have the compiler deal with any alignment
521 // issues on the target architecture
522 memcpy(&ldst, ctx->cursor, sizeof(ldst));
523
524 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930525 ldst = le16toh(ldst);
526
527 // Allow storing to unaligned
528 memcpy(dst, &ldst, sizeof(ldst));
529
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030530 ctx->cursor += sizeof(ldst);
531
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930532 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030533}
534
Andrew Jeffery66c77232024-04-24 11:42:02 +0930535#define pldm_msgbuf_extract_int16(ctx, dst) \
536 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
537 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930538__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930539// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930540pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030541{
542 int16_t ldst;
543
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930544 assert(ctx);
545
546 if (!ctx->cursor || !dst) {
547 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030548 }
549
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930550 static_assert(
551 // NOLINTNEXTLINE(bugprone-sizeof-expression)
552 sizeof(ldst) < INTMAX_MAX,
553 "The following addition may not uphold the runtime assertion");
554 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
555 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930556 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930557 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030558 ctx->remaining -= sizeof(ldst);
559 assert(ctx->remaining >= 0);
560 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930561 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030562 }
563
564 memcpy(&ldst, ctx->cursor, sizeof(ldst));
565
Andrew Jeffery66c77232024-04-24 11:42:02 +0930566 ldst = le16toh(ldst);
567 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030568 ctx->cursor += sizeof(ldst);
569
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930570 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030571}
572
Andrew Jeffery66c77232024-04-24 11:42:02 +0930573#define pldm_msgbuf_extract_uint32(ctx, dst) \
574 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
575 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930576__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930577// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930578pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030579{
580 uint32_t ldst;
581
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930582 assert(ctx);
583
584 if (!ctx->cursor || !dst) {
585 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030586 }
587
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930588 static_assert(
589 // NOLINTNEXTLINE(bugprone-sizeof-expression)
590 sizeof(ldst) < INTMAX_MAX,
591 "The following addition may not uphold the runtime assertion");
592 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
593 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930594 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930595 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030596 ctx->remaining -= sizeof(ldst);
597 assert(ctx->remaining >= 0);
598 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930599 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030600 }
601
602 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930603 ldst = le32toh(ldst);
604 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030605 ctx->cursor += sizeof(ldst);
606
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930607 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030608}
609
Andrew Jeffery66c77232024-04-24 11:42:02 +0930610#define pldm_msgbuf_extract_int32(ctx, dst) \
611 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
612 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930613__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930614// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930615pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030616{
617 int32_t ldst;
618
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930619 assert(ctx);
620
621 if (!ctx->cursor || !dst) {
622 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030623 }
624
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930625 static_assert(
626 // NOLINTNEXTLINE(bugprone-sizeof-expression)
627 sizeof(ldst) < INTMAX_MAX,
628 "The following addition may not uphold the runtime assertion");
629 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
630 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930631 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930632 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030633 ctx->remaining -= sizeof(ldst);
634 assert(ctx->remaining >= 0);
635 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930636 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030637 }
638
639 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930640 ldst = le32toh(ldst);
641 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030642 ctx->cursor += sizeof(ldst);
643
644 return PLDM_SUCCESS;
645}
646
Andrew Jeffery66c77232024-04-24 11:42:02 +0930647#define pldm_msgbuf_extract_real32(ctx, dst) \
648 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
649 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930650__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930651// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930652pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030653{
654 uint32_t ldst;
655
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930656 static_assert(sizeof(real32_t) == sizeof(ldst),
657 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930658
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930659 assert(ctx);
660
661 if (!ctx->cursor || !dst) {
662 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030663 }
664
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930665 static_assert(
666 // NOLINTNEXTLINE(bugprone-sizeof-expression)
667 sizeof(ldst) < INTMAX_MAX,
668 "The following addition may not uphold the runtime assertion");
669 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
670 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930671 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930672 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030673 ctx->remaining -= sizeof(ldst);
674 assert(ctx->remaining >= 0);
675 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930676 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030677 }
678
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030679 memcpy(&ldst, ctx->cursor, sizeof(ldst));
680 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930681 memcpy(dst, &ldst, sizeof(ldst));
682 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030683
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930684 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030685}
686
Andrew Jeffery66c77232024-04-24 11:42:02 +0930687/**
688 * Extract the field at the msgbuf cursor into the lvalue named by dst.
689 *
690 * @param ctx The msgbuf context object
691 * @param dst The lvalue into which the field at the msgbuf cursor should be
692 * extracted
693 *
694 * @return PLDM_SUCCESS on success, otherwise another value on error
695 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030696#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930697 _Generic((dst), \
698 uint8_t: pldm__msgbuf_extract_uint8, \
699 int8_t: pldm__msgbuf_extract_int8, \
700 uint16_t: pldm__msgbuf_extract_uint16, \
701 int16_t: pldm__msgbuf_extract_int16, \
702 uint32_t: pldm__msgbuf_extract_uint32, \
703 int32_t: pldm__msgbuf_extract_int32, \
704 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
705
706/**
707 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
708 *
709 * @param ctx The msgbuf context object
710 * @param dst The pointer to the object into which the field at the msgbuf
711 * cursor should be extracted
712 *
713 * @return PLDM_SUCCESS on success, otherwise another value on error
714 */
715#define pldm_msgbuf_extract_p(ctx, dst) \
716 _Generic((dst), \
717 uint8_t *: pldm__msgbuf_extract_uint8, \
718 int8_t *: pldm__msgbuf_extract_int8, \
719 uint16_t *: pldm__msgbuf_extract_uint16, \
720 int16_t *: pldm__msgbuf_extract_int16, \
721 uint32_t *: pldm__msgbuf_extract_uint32, \
722 int32_t *: pldm__msgbuf_extract_int32, \
723 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030724
Andrew Jeffery76712f62024-05-22 15:19:00 +0930725__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930726// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
727pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, void *dst,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930728 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930729{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930730 assert(ctx);
731
732 if (!ctx->cursor || !dst) {
733 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930734 }
735
736 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930737 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930738 }
739
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930740#if INTMAX_MAX < SIZE_MAX
741 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930742 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930743 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930744#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930745
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930746 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930747 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930748 }
749 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930750 assert(ctx->remaining >= 0);
751 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930752 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930753 }
754
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030755 memcpy(dst, ctx->cursor, count);
756 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930757
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930758 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930759}
760
Andrew Jeffery1c571442024-07-08 10:25:48 +0930761__attribute__((always_inline)) static inline int
762pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, char *dst, size_t count)
763{
764 return pldm__msgbuf_extract_array_void(ctx, dst, count);
765}
766
767__attribute__((always_inline)) static inline int
768pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
769 size_t count)
770{
771 return pldm__msgbuf_extract_array_void(ctx, dst, count);
772}
773
Andrew Jeffery369b1212023-04-20 15:44:48 +0930774#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930775 _Generic((*(dst)), \
776 uint8_t: pldm_msgbuf_extract_array_uint8, \
777 char: pldm_msgbuf_extract_array_char)(ctx, dst, count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930778
Andrew Jeffery76712f62024-05-22 15:19:00 +0930779__attribute__((always_inline)) static inline int
780pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700781{
782 uint32_t val = htole32(src);
783
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930784 assert(ctx);
785
786 if (!ctx->cursor) {
787 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700788 }
789
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930790 static_assert(
791 // NOLINTNEXTLINE(bugprone-sizeof-expression)
792 sizeof(src) < INTMAX_MAX,
793 "The following addition may not uphold the runtime assertion");
794 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
795 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930796 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930797 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700798 ctx->remaining -= sizeof(src);
799 assert(ctx->remaining >= 0);
800 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930801 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700802 }
803
804 memcpy(ctx->cursor, &val, sizeof(val));
805 ctx->cursor += sizeof(src);
806
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930807 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700808}
809
Andrew Jeffery76712f62024-05-22 15:19:00 +0930810__attribute__((always_inline)) static inline int
811pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700812{
813 uint16_t val = htole16(src);
814
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930815 assert(ctx);
816
817 if (!ctx->cursor) {
818 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700819 }
820
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930821 static_assert(
822 // NOLINTNEXTLINE(bugprone-sizeof-expression)
823 sizeof(src) < INTMAX_MAX,
824 "The following addition may not uphold the runtime assertion");
825 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
826 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930827 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930828 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700829 ctx->remaining -= sizeof(src);
830 assert(ctx->remaining >= 0);
831 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930832 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700833 }
834
835 memcpy(ctx->cursor, &val, sizeof(val));
836 ctx->cursor += sizeof(src);
837
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930838 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700839}
840
Andrew Jeffery76712f62024-05-22 15:19:00 +0930841__attribute__((always_inline)) static inline int
842pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700843{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930844 assert(ctx);
845
846 if (!ctx->cursor) {
847 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700848 }
849
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930850 static_assert(
851 // NOLINTNEXTLINE(bugprone-sizeof-expression)
852 sizeof(src) < INTMAX_MAX,
853 "The following addition may not uphold the runtime assertion");
854 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
855 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930856 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930857 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700858 ctx->remaining -= sizeof(src);
859 assert(ctx->remaining >= 0);
860 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930861 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700862 }
863
864 memcpy(ctx->cursor, &src, sizeof(src));
865 ctx->cursor += sizeof(src);
866
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930867 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700868}
869
Andrew Jeffery76712f62024-05-22 15:19:00 +0930870__attribute__((always_inline)) static inline int
871pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700872{
873 int32_t val = htole32(src);
874
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930875 assert(ctx);
876
877 if (!ctx->cursor) {
878 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700879 }
880
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930881 static_assert(
882 // NOLINTNEXTLINE(bugprone-sizeof-expression)
883 sizeof(src) < INTMAX_MAX,
884 "The following addition may not uphold the runtime assertion");
885 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
886 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930887 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930888 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700889 ctx->remaining -= sizeof(src);
890 assert(ctx->remaining >= 0);
891 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930892 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700893 }
894
895 memcpy(ctx->cursor, &val, sizeof(val));
896 ctx->cursor += sizeof(src);
897
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930898 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700899}
900
Andrew Jeffery76712f62024-05-22 15:19:00 +0930901__attribute__((always_inline)) static inline int
902pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700903{
904 int16_t val = htole16(src);
905
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930906 assert(ctx);
907
908 if (!ctx->cursor) {
909 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700910 }
911
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930912 static_assert(
913 // NOLINTNEXTLINE(bugprone-sizeof-expression)
914 sizeof(src) < INTMAX_MAX,
915 "The following addition may not uphold the runtime assertion");
916 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
917 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930918 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930919 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700920 ctx->remaining -= sizeof(src);
921 assert(ctx->remaining >= 0);
922 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930923 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700924 }
925
926 memcpy(ctx->cursor, &val, sizeof(val));
927 ctx->cursor += sizeof(src);
928
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930929 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700930}
931
Andrew Jeffery76712f62024-05-22 15:19:00 +0930932__attribute__((always_inline)) static inline int
933pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700934{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930935 assert(ctx);
936
937 if (!ctx->cursor) {
938 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700939 }
940
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930941 static_assert(
942 // NOLINTNEXTLINE(bugprone-sizeof-expression)
943 sizeof(src) < INTMAX_MAX,
944 "The following addition may not uphold the runtime assertion");
945 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
946 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930947 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930948 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700949 ctx->remaining -= sizeof(src);
950 assert(ctx->remaining >= 0);
951 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930952 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700953 }
954
955 memcpy(ctx->cursor, &src, sizeof(src));
956 ctx->cursor += sizeof(src);
957
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930958 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700959}
960
961#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930962 _Generic((src), \
963 uint8_t: pldm_msgbuf_insert_uint8, \
964 int8_t: pldm_msgbuf_insert_int8, \
965 uint16_t: pldm_msgbuf_insert_uint16, \
966 int16_t: pldm_msgbuf_insert_int16, \
967 uint32_t: pldm_msgbuf_insert_uint32, \
968 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700969
Andrew Jeffery76712f62024-05-22 15:19:00 +0930970__attribute__((always_inline)) static inline int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930971// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
972pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, const void *src,
Andrew Jeffery76712f62024-05-22 15:19:00 +0930973 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700974{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930975 assert(ctx);
976
977 if (!ctx->cursor || !src) {
978 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700979 }
980
981 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930982 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700983 }
984
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930985#if INTMAX_MAX < SIZE_MAX
986 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930987 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700988 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930989#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700990
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930991 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930992 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930993 }
994 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700995 assert(ctx->remaining >= 0);
996 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930997 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700998 }
999
Andrew Jefferya065ecc2023-10-27 15:02:11 +10301000 memcpy(ctx->cursor, src, count);
1001 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001002
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301003 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001004}
1005
Andrew Jeffery1c571442024-07-08 10:25:48 +09301006__attribute__((always_inline)) static inline int
1007pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, const char *src,
1008 size_t count)
1009{
1010 return pldm__msgbuf_insert_array_void(ctx, src, count);
1011}
1012
1013__attribute__((always_inline)) static inline int
1014pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
1015 size_t count)
1016{
1017 return pldm__msgbuf_insert_array_void(ctx, src, count);
1018}
1019
Thu Nguyen062c8762023-04-22 20:45:04 +07001020#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +09301021 _Generic((*(src)), \
1022 uint8_t: pldm_msgbuf_insert_array_uint8, \
1023 char: pldm_msgbuf_insert_array_char)(dst, src, count)
Thu Nguyen062c8762023-04-22 20:45:04 +07001024
Andrew Jeffery76712f62024-05-22 15:19:00 +09301025__attribute__((always_inline)) static inline int
1026pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
1027 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +07001028{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301029 assert(ctx);
1030
1031 if (!ctx->cursor || !cursor || *cursor) {
1032 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001033 }
1034
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301035#if INTMAX_MAX < SIZE_MAX
1036 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301037 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001038 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301039#endif
Thu Nguyen062c8762023-04-22 20:45:04 +07001040
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301041 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301042 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301043 }
1044 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +07001045 assert(ctx->remaining >= 0);
1046 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301047 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001048 }
1049
1050 *cursor = ctx->cursor;
1051 ctx->cursor += required;
1052
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301053 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001054}
1055
Andrew Jeffery76712f62024-05-22 15:19:00 +09301056__attribute__((always_inline)) static inline int
1057pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001058{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301059 assert(ctx);
1060
1061 if (!ctx->cursor || !cursor || *cursor || !len) {
1062 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001063 }
1064
1065 assert(ctx->remaining >= 0);
1066 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301067 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001068 }
1069
1070 *cursor = ctx->cursor;
1071 ctx->cursor += ctx->remaining;
1072 *len = ctx->remaining;
1073 ctx->remaining = 0;
1074
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301075 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001076}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001077
1078/**
1079 * @brief pldm_msgbuf copy data between two msg buffers
1080 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301081 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1082 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001083 * @param[in] size - size of data to be copied
1084 * @param[in] description - description of data copied
1085 *
1086 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1087 * PLDM_ERROR_INVALID_LENGTH otherwise.
1088 * PLDM_ERROR_INVALID_DATA if input is invalid
1089 */
1090#define pldm_msgbuf_copy(dst, src, type, name) \
1091 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301092__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001093// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301094pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
1095 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001096{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301097 assert(src);
1098 assert(dst);
1099 assert(src->mode == dst->mode);
1100
1101 if (!src->cursor || !dst->cursor || !description) {
1102 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001103 }
1104
1105#if INTMAX_MAX < SIZE_MAX
1106 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301107 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001108 }
1109#endif
1110
1111 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301112 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001113 }
1114
1115 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301116 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001117 }
1118
1119 src->remaining -= (intmax_t)size;
1120 assert(src->remaining >= 0);
1121 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301122 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001123 }
1124
1125 dst->remaining -= (intmax_t)size;
1126 assert(dst->remaining >= 0);
1127 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301128 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001129 }
1130
1131 memcpy(dst->cursor, src->cursor, size);
1132 src->cursor += size;
1133 dst->cursor += size;
1134
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301135 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001136}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301137
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301138#ifdef __cplusplus
1139}
1140#endif
1141
Andrew Jeffery66c77232024-04-24 11:42:02 +09301142#ifdef __cplusplus
1143#include <type_traits>
1144
1145template <typename T>
1146static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1147 void *buf)
1148{
1149 static_assert(std::is_same<uint8_t *, T>::value);
1150 return pldm__msgbuf_extract_uint8(ctx, buf);
1151}
1152
1153template <typename T>
1154static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1155 void *buf)
1156{
1157 static_assert(std::is_same<int8_t *, T>::value);
1158 return pldm__msgbuf_extract_int8(ctx, buf);
1159}
1160
1161template <typename T>
1162static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1163 void *buf)
1164{
1165 static_assert(std::is_same<uint16_t *, T>::value);
1166 return pldm__msgbuf_extract_uint16(ctx, buf);
1167}
1168
1169template <typename T>
1170static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1171 void *buf)
1172{
1173 static_assert(std::is_same<int16_t *, T>::value);
1174 return pldm__msgbuf_extract_int16(ctx, buf);
1175}
1176
1177template <typename T>
1178static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1179 void *buf)
1180{
1181 static_assert(std::is_same<uint32_t *, T>::value);
1182 return pldm__msgbuf_extract_uint32(ctx, buf);
1183}
1184
1185template <typename T>
1186static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1187 void *buf)
1188{
1189 static_assert(std::is_same<int32_t *, T>::value);
1190 return pldm__msgbuf_extract_int32(ctx, buf);
1191}
1192
1193template <typename T>
1194static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1195 void *buf)
1196{
1197 static_assert(std::is_same<real32_t *, T>::value);
1198 return pldm__msgbuf_extract_real32(ctx, buf);
1199}
1200#endif
1201
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301202#endif /* BUF_H */