xref: /openbmc/libpldm/src/msgbuf.h (revision 37dd6a3d)
1c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H
2c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H
3c63f63a2SAndrew Jeffery 
4c63f63a2SAndrew Jeffery #ifdef __cplusplus
5*37dd6a3dSAndrew Jeffery /*
6*37dd6a3dSAndrew Jeffery  * Fix up C11's _Static_assert() vs C++'s static_assert().
7*37dd6a3dSAndrew Jeffery  *
8*37dd6a3dSAndrew Jeffery  * Can we please have nice things for once.
9*37dd6a3dSAndrew Jeffery  */
10*37dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
11*37dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__)
12c63f63a2SAndrew Jeffery extern "C" {
13c63f63a2SAndrew Jeffery #endif
14c63f63a2SAndrew Jeffery 
15c63f63a2SAndrew Jeffery #include "base.h"
16c63f63a2SAndrew Jeffery #include "pldm_types.h"
17c63f63a2SAndrew Jeffery 
18c63f63a2SAndrew Jeffery #include <assert.h>
19c63f63a2SAndrew Jeffery #include <endian.h>
20c63f63a2SAndrew Jeffery #include <limits.h>
21c63f63a2SAndrew Jeffery #include <stdbool.h>
22c63f63a2SAndrew Jeffery #include <string.h>
23c63f63a2SAndrew Jeffery #include <sys/types.h>
24c63f63a2SAndrew Jeffery 
25062c8762SThu Nguyen /*
26062c8762SThu Nguyen  * Fix up C11's _Static_assert() vs C++'s static_assert().
27062c8762SThu Nguyen  *
28062c8762SThu Nguyen  * Can we please have nice things for once.
29062c8762SThu Nguyen  */
30062c8762SThu Nguyen #ifdef __cplusplus
31062c8762SThu Nguyen // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
32062c8762SThu Nguyen #define _Static_assert(...) static_assert(__VA_ARGS__)
33062c8762SThu Nguyen #endif
34062c8762SThu Nguyen 
35c63f63a2SAndrew Jeffery struct pldm_msgbuf {
36062c8762SThu Nguyen 	uint8_t *cursor;
37c63f63a2SAndrew Jeffery 	ssize_t remaining;
38c63f63a2SAndrew Jeffery };
39c63f63a2SAndrew Jeffery 
40c63f63a2SAndrew Jeffery /**
41c63f63a2SAndrew Jeffery  * @brief Initialize pldm buf struct for buf extractor
42c63f63a2SAndrew Jeffery  *
43c63f63a2SAndrew Jeffery  * @param[out] ctx - pldm_msgbuf context for extractor
44c63f63a2SAndrew Jeffery  * @param[in] minsize - The minimum required length of buffer `buf`
45c63f63a2SAndrew Jeffery  * @param[in] buf - buffer to be extracted
46c63f63a2SAndrew Jeffery  * @param[in] len - size of buffer
47c63f63a2SAndrew Jeffery  *
48c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
49c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or
50c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
51c63f63a2SAndrew Jeffery  */
525646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int
535646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
545646f23bSAndrew Jeffery 		 size_t len)
55c63f63a2SAndrew Jeffery {
56c63f63a2SAndrew Jeffery 	uint8_t *end;
57c63f63a2SAndrew Jeffery 
58c63f63a2SAndrew Jeffery 	if (!ctx || !buf) {
59c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
60c63f63a2SAndrew Jeffery 	}
61c63f63a2SAndrew Jeffery 
62c63f63a2SAndrew Jeffery 	if ((minsize > len) || (len > SSIZE_MAX)) {
63c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
64c63f63a2SAndrew Jeffery 	}
65c63f63a2SAndrew Jeffery 
66c63f63a2SAndrew Jeffery 	end = (uint8_t *)buf + len;
67c63f63a2SAndrew Jeffery 	if (end && end < (uint8_t *)buf) {
68c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
69c63f63a2SAndrew Jeffery 	}
70c63f63a2SAndrew Jeffery 
71c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
72c63f63a2SAndrew Jeffery 	ctx->remaining = (ssize_t)len;
73c63f63a2SAndrew Jeffery 
74c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
75c63f63a2SAndrew Jeffery }
76c63f63a2SAndrew Jeffery 
77c63f63a2SAndrew Jeffery /**
78c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
79c63f63a2SAndrew Jeffery  *
80c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
81c63f63a2SAndrew Jeffery  *
82c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
83c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
84c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
85c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
86c63f63a2SAndrew Jeffery  * pointer.
87c63f63a2SAndrew Jeffery  */
88c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
89c63f63a2SAndrew Jeffery {
90c63f63a2SAndrew Jeffery 	if (!ctx) {
91c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
92c63f63a2SAndrew Jeffery 	}
93c63f63a2SAndrew Jeffery 
94c63f63a2SAndrew Jeffery 	return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
95c63f63a2SAndrew Jeffery }
96c63f63a2SAndrew Jeffery 
97c63f63a2SAndrew Jeffery /**
98db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
99db7b8324SAndrew Jeffery  *
100db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
101db7b8324SAndrew Jeffery  *
102db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
103db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
104db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
105db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
106db7b8324SAndrew Jeffery  * pointer.
107db7b8324SAndrew Jeffery  */
108db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
109db7b8324SAndrew Jeffery {
110db7b8324SAndrew Jeffery 	if (!ctx) {
111db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
112db7b8324SAndrew Jeffery 	}
113db7b8324SAndrew Jeffery 
114db7b8324SAndrew Jeffery 	return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
115db7b8324SAndrew Jeffery }
116db7b8324SAndrew Jeffery 
117db7b8324SAndrew Jeffery /**
118c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
119c63f63a2SAndrew Jeffery  *
120c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
121c63f63a2SAndrew Jeffery  *
122c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
123c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
124c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
125c63f63a2SAndrew Jeffery  * bounds of the buffer.
126c63f63a2SAndrew Jeffery  */
127c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
128c63f63a2SAndrew Jeffery {
129c63f63a2SAndrew Jeffery 	int valid;
130c63f63a2SAndrew Jeffery 
131c63f63a2SAndrew Jeffery 	if (!ctx) {
132c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
133c63f63a2SAndrew Jeffery 	}
134c63f63a2SAndrew Jeffery 
135c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
136c63f63a2SAndrew Jeffery 
137c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
138c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
139c63f63a2SAndrew Jeffery 
140c63f63a2SAndrew Jeffery 	return valid;
141c63f63a2SAndrew Jeffery }
142c63f63a2SAndrew Jeffery 
143c63f63a2SAndrew Jeffery /**
144db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
145db7b8324SAndrew Jeffery  * has been completely consumed without overflow
146db7b8324SAndrew Jeffery  *
147db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
148db7b8324SAndrew Jeffery  *
149db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
150db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
151db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
152db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
153db7b8324SAndrew Jeffery  */
154db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
155db7b8324SAndrew Jeffery {
156db7b8324SAndrew Jeffery 	int consumed;
157db7b8324SAndrew Jeffery 
158db7b8324SAndrew Jeffery 	if (!ctx) {
159db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
160db7b8324SAndrew Jeffery 	}
161db7b8324SAndrew Jeffery 
162db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
163db7b8324SAndrew Jeffery 
164db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
165db7b8324SAndrew Jeffery 	ctx->remaining = 0;
166db7b8324SAndrew Jeffery 
167db7b8324SAndrew Jeffery 	return consumed;
168db7b8324SAndrew Jeffery }
169db7b8324SAndrew Jeffery 
170db7b8324SAndrew Jeffery /**
171c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
172c63f63a2SAndrew Jeffery  *
173c63f63a2SAndrew Jeffery  * @param[inout] ctx - pldm_msgbuf context for extractor
174c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
175c63f63a2SAndrew Jeffery  *
176c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
177c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
178c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
179c63f63a2SAndrew Jeffery  */
180c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx,
181c63f63a2SAndrew Jeffery 					    uint8_t *dst)
182c63f63a2SAndrew Jeffery {
183c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
184c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
185c63f63a2SAndrew Jeffery 	}
186c63f63a2SAndrew Jeffery 
187c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
188c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
189c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
190c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
191c63f63a2SAndrew Jeffery 	}
192c63f63a2SAndrew Jeffery 
193c63f63a2SAndrew Jeffery 	*dst = *((uint8_t *)(ctx->cursor));
194c63f63a2SAndrew Jeffery 	ctx->cursor++;
195c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
196c63f63a2SAndrew Jeffery }
197c63f63a2SAndrew Jeffery 
198c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst)
199c63f63a2SAndrew Jeffery {
200c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
201c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
202c63f63a2SAndrew Jeffery 	}
203c63f63a2SAndrew Jeffery 
204c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
205c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
206c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
207c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
208c63f63a2SAndrew Jeffery 	}
209c63f63a2SAndrew Jeffery 
210c63f63a2SAndrew Jeffery 	*dst = *((int8_t *)(ctx->cursor));
211c63f63a2SAndrew Jeffery 	ctx->cursor++;
212c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
213c63f63a2SAndrew Jeffery }
214c63f63a2SAndrew Jeffery 
215c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx,
216c63f63a2SAndrew Jeffery 					     uint16_t *dst)
217c63f63a2SAndrew Jeffery {
218c63f63a2SAndrew Jeffery 	uint16_t ldst;
219c63f63a2SAndrew Jeffery 
220c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
221c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
222c63f63a2SAndrew Jeffery 	}
223c63f63a2SAndrew Jeffery 
224c63f63a2SAndrew Jeffery 	// Check for buffer overflow. If we overflow, account for the request as
225c63f63a2SAndrew Jeffery 	// negative values in ctx->remaining. This way we can debug how far
226c63f63a2SAndrew Jeffery 	// we've overflowed.
227c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
228c63f63a2SAndrew Jeffery 
229c63f63a2SAndrew Jeffery 	// Prevent the access if it would overflow. First, assert so we blow up
230c63f63a2SAndrew Jeffery 	// the test suite right at the point of failure. However, cater to
231c63f63a2SAndrew Jeffery 	// -DNDEBUG by explicitly testing that the access is valid.
232c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
233c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
234c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
235c63f63a2SAndrew Jeffery 	}
236c63f63a2SAndrew Jeffery 
237c63f63a2SAndrew Jeffery 	// Use memcpy() to have the compiler deal with any alignment
238c63f63a2SAndrew Jeffery 	// issues on the target architecture
239c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
240c63f63a2SAndrew Jeffery 
241c63f63a2SAndrew Jeffery 	// Only assign the target value once it's correctly decoded
242c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
243c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
244c63f63a2SAndrew Jeffery 
245c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
246c63f63a2SAndrew Jeffery }
247c63f63a2SAndrew Jeffery 
248c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx,
249c63f63a2SAndrew Jeffery 					    int16_t *dst)
250c63f63a2SAndrew Jeffery {
251c63f63a2SAndrew Jeffery 	int16_t ldst;
252c63f63a2SAndrew Jeffery 
253c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
254c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
255c63f63a2SAndrew Jeffery 	}
256c63f63a2SAndrew Jeffery 
257c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
258c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
259c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
260c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
261c63f63a2SAndrew Jeffery 	}
262c63f63a2SAndrew Jeffery 
263c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
264c63f63a2SAndrew Jeffery 
265c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
266c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
267c63f63a2SAndrew Jeffery 
268c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
269c63f63a2SAndrew Jeffery }
270c63f63a2SAndrew Jeffery 
271c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx,
272c63f63a2SAndrew Jeffery 					     uint32_t *dst)
273c63f63a2SAndrew Jeffery {
274c63f63a2SAndrew Jeffery 	uint32_t ldst;
275c63f63a2SAndrew Jeffery 
276c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
277c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
278c63f63a2SAndrew Jeffery 	}
279c63f63a2SAndrew Jeffery 
280c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
281c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
282c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
283c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
284c63f63a2SAndrew Jeffery 	}
285c63f63a2SAndrew Jeffery 
286c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
287c63f63a2SAndrew Jeffery 
288c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
289c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
290c63f63a2SAndrew Jeffery 
291c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
292c63f63a2SAndrew Jeffery }
293c63f63a2SAndrew Jeffery 
294c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx,
295c63f63a2SAndrew Jeffery 					    int32_t *dst)
296c63f63a2SAndrew Jeffery {
297c63f63a2SAndrew Jeffery 	int32_t ldst;
298c63f63a2SAndrew Jeffery 
299c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
300c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
301c63f63a2SAndrew Jeffery 	}
302c63f63a2SAndrew Jeffery 
303c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
304c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
305c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
306c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
307c63f63a2SAndrew Jeffery 	}
308c63f63a2SAndrew Jeffery 
309c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
310c63f63a2SAndrew Jeffery 
311c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
312c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
313c63f63a2SAndrew Jeffery 
314c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
315c63f63a2SAndrew Jeffery }
316c63f63a2SAndrew Jeffery 
317c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx,
318c63f63a2SAndrew Jeffery 					     real32_t *dst)
319c63f63a2SAndrew Jeffery {
320c63f63a2SAndrew Jeffery 	uint32_t ldst;
321c63f63a2SAndrew Jeffery 
322c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
323c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
324c63f63a2SAndrew Jeffery 	}
325c63f63a2SAndrew Jeffery 
326c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
327c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
328c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
329c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
330c63f63a2SAndrew Jeffery 	}
331c63f63a2SAndrew Jeffery 
332c63f63a2SAndrew Jeffery 	_Static_assert(sizeof(*dst) == sizeof(ldst),
333c63f63a2SAndrew Jeffery 		       "Mismatched type sizes for dst and ldst");
334c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
335c63f63a2SAndrew Jeffery 	ldst = le32toh(ldst);
336c63f63a2SAndrew Jeffery 	memcpy(dst, &ldst, sizeof(*dst));
337c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(*dst);
338c63f63a2SAndrew Jeffery 
339c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
340c63f63a2SAndrew Jeffery }
341c63f63a2SAndrew Jeffery 
342c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
343*37dd6a3dSAndrew Jeffery 	_Generic((*(dst)),                                                     \
344*37dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_extract_uint8,                            \
345*37dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_extract_int8,                              \
346*37dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_extract_uint16,                          \
347*37dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_extract_int16,                            \
348*37dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_extract_uint32,                          \
349*37dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_extract_int32,                            \
350*37dd6a3dSAndrew Jeffery 		real32_t: pldm_msgbuf_extract_real32)(ctx, dst)
351c63f63a2SAndrew Jeffery 
352369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx,
353369b121aSAndrew Jeffery 						  uint8_t *dst, size_t count)
354369b121aSAndrew Jeffery {
355369b121aSAndrew Jeffery 	size_t len;
356369b121aSAndrew Jeffery 
357369b121aSAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
358369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
359369b121aSAndrew Jeffery 	}
360369b121aSAndrew Jeffery 
361369b121aSAndrew Jeffery 	if (!count) {
362369b121aSAndrew Jeffery 		return PLDM_SUCCESS;
363369b121aSAndrew Jeffery 	}
364369b121aSAndrew Jeffery 
365369b121aSAndrew Jeffery 	len = sizeof(*dst) * count;
366369b121aSAndrew Jeffery 	if (len > SSIZE_MAX) {
367369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
368369b121aSAndrew Jeffery 	}
369369b121aSAndrew Jeffery 
370369b121aSAndrew Jeffery 	ctx->remaining -= (ssize_t)len;
371369b121aSAndrew Jeffery 	assert(ctx->remaining >= 0);
372369b121aSAndrew Jeffery 	if (ctx->remaining < 0) {
373369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
374369b121aSAndrew Jeffery 	}
375369b121aSAndrew Jeffery 
376369b121aSAndrew Jeffery 	memcpy(dst, ctx->cursor, len);
377369b121aSAndrew Jeffery 	ctx->cursor += len;
378369b121aSAndrew Jeffery 
379369b121aSAndrew Jeffery 	return PLDM_SUCCESS;
380369b121aSAndrew Jeffery }
381369b121aSAndrew Jeffery 
382369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
383*37dd6a3dSAndrew Jeffery 	_Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
384*37dd6a3dSAndrew Jeffery 								     count)
385369b121aSAndrew Jeffery 
386062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
387062c8762SThu Nguyen 					    const uint32_t src)
388062c8762SThu Nguyen {
389062c8762SThu Nguyen 	uint32_t val = htole32(src);
390062c8762SThu Nguyen 
391062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
392062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
393062c8762SThu Nguyen 	}
394062c8762SThu Nguyen 
395062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
396062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
397062c8762SThu Nguyen 	if (ctx->remaining < 0) {
398062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
399062c8762SThu Nguyen 	}
400062c8762SThu Nguyen 
401062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
402062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
403062c8762SThu Nguyen 
404062c8762SThu Nguyen 	return PLDM_SUCCESS;
405062c8762SThu Nguyen }
406062c8762SThu Nguyen 
407062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
408062c8762SThu Nguyen 					    const uint16_t src)
409062c8762SThu Nguyen {
410062c8762SThu Nguyen 	uint16_t val = htole16(src);
411062c8762SThu Nguyen 
412062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
413062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
414062c8762SThu Nguyen 	}
415062c8762SThu Nguyen 
416062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
417062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
418062c8762SThu Nguyen 	if (ctx->remaining < 0) {
419062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
420062c8762SThu Nguyen 	}
421062c8762SThu Nguyen 
422062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
423062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
424062c8762SThu Nguyen 
425062c8762SThu Nguyen 	return PLDM_SUCCESS;
426062c8762SThu Nguyen }
427062c8762SThu Nguyen 
428062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
429062c8762SThu Nguyen 					   const uint8_t src)
430062c8762SThu Nguyen {
431062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
432062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
433062c8762SThu Nguyen 	}
434062c8762SThu Nguyen 
435062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
436062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
437062c8762SThu Nguyen 	if (ctx->remaining < 0) {
438062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
439062c8762SThu Nguyen 	}
440062c8762SThu Nguyen 
441062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
442062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
443062c8762SThu Nguyen 
444062c8762SThu Nguyen 	return PLDM_SUCCESS;
445062c8762SThu Nguyen }
446062c8762SThu Nguyen 
447062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
448062c8762SThu Nguyen 					   const int32_t src)
449062c8762SThu Nguyen {
450062c8762SThu Nguyen 	int32_t val = htole32(src);
451062c8762SThu Nguyen 
452062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
453062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
454062c8762SThu Nguyen 	}
455062c8762SThu Nguyen 
456062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
457062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
458062c8762SThu Nguyen 	if (ctx->remaining < 0) {
459062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
460062c8762SThu Nguyen 	}
461062c8762SThu Nguyen 
462062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
463062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
464062c8762SThu Nguyen 
465062c8762SThu Nguyen 	return PLDM_SUCCESS;
466062c8762SThu Nguyen }
467062c8762SThu Nguyen 
468062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
469062c8762SThu Nguyen 					   const int16_t src)
470062c8762SThu Nguyen {
471062c8762SThu Nguyen 	int16_t val = htole16(src);
472062c8762SThu Nguyen 
473062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
474062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
475062c8762SThu Nguyen 	}
476062c8762SThu Nguyen 
477062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
478062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
479062c8762SThu Nguyen 	if (ctx->remaining < 0) {
480062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
481062c8762SThu Nguyen 	}
482062c8762SThu Nguyen 
483062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
484062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
485062c8762SThu Nguyen 
486062c8762SThu Nguyen 	return PLDM_SUCCESS;
487062c8762SThu Nguyen }
488062c8762SThu Nguyen 
489062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
490062c8762SThu Nguyen 					  const int8_t src)
491062c8762SThu Nguyen {
492062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
493062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
494062c8762SThu Nguyen 	}
495062c8762SThu Nguyen 
496062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
497062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
498062c8762SThu Nguyen 	if (ctx->remaining < 0) {
499062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
500062c8762SThu Nguyen 	}
501062c8762SThu Nguyen 
502062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
503062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
504062c8762SThu Nguyen 
505062c8762SThu Nguyen 	return PLDM_SUCCESS;
506062c8762SThu Nguyen }
507062c8762SThu Nguyen 
508062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
509*37dd6a3dSAndrew Jeffery 	_Generic((src),                                                        \
510*37dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_uint8,                             \
511*37dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_insert_int8,                               \
512*37dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_insert_uint16,                           \
513*37dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_insert_int16,                             \
514*37dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_insert_uint32,                           \
515*37dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_insert_int32)(dst, src)
516062c8762SThu Nguyen 
517062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx,
518062c8762SThu Nguyen 						 const uint8_t *src,
519062c8762SThu Nguyen 						 size_t count)
520062c8762SThu Nguyen {
521062c8762SThu Nguyen 	size_t len;
522062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !src) {
523062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
524062c8762SThu Nguyen 	}
525062c8762SThu Nguyen 
526062c8762SThu Nguyen 	if (!count) {
527062c8762SThu Nguyen 		return PLDM_SUCCESS;
528062c8762SThu Nguyen 	}
529062c8762SThu Nguyen 
530062c8762SThu Nguyen 	len = sizeof(*src) * count;
531062c8762SThu Nguyen 	if (len > SSIZE_MAX) {
532062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
533062c8762SThu Nguyen 	}
534062c8762SThu Nguyen 
535062c8762SThu Nguyen 	ctx->remaining -= (ssize_t)len;
536062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
537062c8762SThu Nguyen 	if (ctx->remaining < 0) {
538062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
539062c8762SThu Nguyen 	}
540062c8762SThu Nguyen 
541062c8762SThu Nguyen 	memcpy(ctx->cursor, src, len);
542062c8762SThu Nguyen 	ctx->cursor += len;
543062c8762SThu Nguyen 
544062c8762SThu Nguyen 	return PLDM_SUCCESS;
545062c8762SThu Nguyen }
546062c8762SThu Nguyen 
547062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count)                              \
548*37dd6a3dSAndrew Jeffery 	_Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src,  \
549*37dd6a3dSAndrew Jeffery 								    count)
550062c8762SThu Nguyen 
551062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
552062c8762SThu Nguyen 					    size_t required, void **cursor)
553062c8762SThu Nguyen {
554062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor) {
555062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
556062c8762SThu Nguyen 	}
557062c8762SThu Nguyen 
558062c8762SThu Nguyen 	if (required > SSIZE_MAX) {
559062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
560062c8762SThu Nguyen 	}
561062c8762SThu Nguyen 
562062c8762SThu Nguyen 	ctx->remaining -= (ssize_t)required;
563062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
564062c8762SThu Nguyen 	if (ctx->remaining < 0) {
565062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
566062c8762SThu Nguyen 	}
567062c8762SThu Nguyen 
568062c8762SThu Nguyen 	*cursor = ctx->cursor;
569062c8762SThu Nguyen 	ctx->cursor += required;
570062c8762SThu Nguyen 
571062c8762SThu Nguyen 	return PLDM_SUCCESS;
572062c8762SThu Nguyen }
573062c8762SThu Nguyen 
574062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx,
575062c8762SThu Nguyen 					     void **cursor, size_t *len)
576062c8762SThu Nguyen {
577062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
578062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
579062c8762SThu Nguyen 	}
580062c8762SThu Nguyen 
581062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
582062c8762SThu Nguyen 	if (ctx->remaining < 0) {
583062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
584062c8762SThu Nguyen 	}
585062c8762SThu Nguyen 
586062c8762SThu Nguyen 	*cursor = ctx->cursor;
587062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
588062c8762SThu Nguyen 	*len = ctx->remaining;
589062c8762SThu Nguyen 	ctx->remaining = 0;
590062c8762SThu Nguyen 
591062c8762SThu Nguyen 	return PLDM_SUCCESS;
592062c8762SThu Nguyen }
593c63f63a2SAndrew Jeffery #ifdef __cplusplus
594c63f63a2SAndrew Jeffery }
595c63f63a2SAndrew Jeffery #endif
596c63f63a2SAndrew Jeffery 
597c63f63a2SAndrew Jeffery #endif /* BUF_H */
598