xref: /openbmc/libpldm/src/msgbuf.h (revision a065eccb)
1691668feSPatrick Williams /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H
3c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H
4c63f63a2SAndrew Jeffery 
5c63f63a2SAndrew Jeffery #ifdef __cplusplus
637dd6a3dSAndrew Jeffery /*
737dd6a3dSAndrew Jeffery  * Fix up C11's _Static_assert() vs C++'s static_assert().
837dd6a3dSAndrew Jeffery  *
937dd6a3dSAndrew Jeffery  * Can we please have nice things for once.
1037dd6a3dSAndrew Jeffery  */
1137dd6a3dSAndrew Jeffery // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
1237dd6a3dSAndrew Jeffery #define _Static_assert(...) static_assert(__VA_ARGS__)
13c63f63a2SAndrew Jeffery extern "C" {
14c63f63a2SAndrew Jeffery #endif
15c63f63a2SAndrew Jeffery 
16b0c1d20aSAndrew Jeffery #include <libpldm/base.h>
17b0c1d20aSAndrew Jeffery #include <libpldm/pldm_types.h>
18c63f63a2SAndrew Jeffery 
19c63f63a2SAndrew Jeffery #include <assert.h>
20c63f63a2SAndrew Jeffery #include <endian.h>
21c63f63a2SAndrew Jeffery #include <limits.h>
22c63f63a2SAndrew Jeffery #include <stdbool.h>
23c63f63a2SAndrew Jeffery #include <string.h>
24c63f63a2SAndrew Jeffery #include <sys/types.h>
25c63f63a2SAndrew Jeffery 
26c63f63a2SAndrew Jeffery struct pldm_msgbuf {
27062c8762SThu Nguyen 	uint8_t *cursor;
28c63f63a2SAndrew Jeffery 	ssize_t remaining;
29c63f63a2SAndrew Jeffery };
30c63f63a2SAndrew Jeffery 
31c63f63a2SAndrew Jeffery /**
32c63f63a2SAndrew Jeffery  * @brief Initialize pldm buf struct for buf extractor
33c63f63a2SAndrew Jeffery  *
34c63f63a2SAndrew Jeffery  * @param[out] ctx - pldm_msgbuf context for extractor
35c63f63a2SAndrew Jeffery  * @param[in] minsize - The minimum required length of buffer `buf`
36c63f63a2SAndrew Jeffery  * @param[in] buf - buffer to be extracted
37c63f63a2SAndrew Jeffery  * @param[in] len - size of buffer
38c63f63a2SAndrew Jeffery  *
39c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
40c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or
41c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
42c63f63a2SAndrew Jeffery  */
435646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int
445646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
455646f23bSAndrew Jeffery 		 size_t len)
46c63f63a2SAndrew Jeffery {
47c63f63a2SAndrew Jeffery 	uint8_t *end;
48c63f63a2SAndrew Jeffery 
49c63f63a2SAndrew Jeffery 	if (!ctx || !buf) {
50c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
51c63f63a2SAndrew Jeffery 	}
52c63f63a2SAndrew Jeffery 
53c63f63a2SAndrew Jeffery 	if ((minsize > len) || (len > SSIZE_MAX)) {
54c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
55c63f63a2SAndrew Jeffery 	}
56c63f63a2SAndrew Jeffery 
57c63f63a2SAndrew Jeffery 	end = (uint8_t *)buf + len;
58c63f63a2SAndrew Jeffery 	if (end && end < (uint8_t *)buf) {
59c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
60c63f63a2SAndrew Jeffery 	}
61c63f63a2SAndrew Jeffery 
62c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
63c63f63a2SAndrew Jeffery 	ctx->remaining = (ssize_t)len;
64c63f63a2SAndrew Jeffery 
65c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
66c63f63a2SAndrew Jeffery }
67c63f63a2SAndrew Jeffery 
68c63f63a2SAndrew Jeffery /**
69c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
70c63f63a2SAndrew Jeffery  *
71c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
72c63f63a2SAndrew Jeffery  *
73c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
74c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
75c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
76c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
77c63f63a2SAndrew Jeffery  * pointer.
78c63f63a2SAndrew Jeffery  */
79c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
80c63f63a2SAndrew Jeffery {
81c63f63a2SAndrew Jeffery 	if (!ctx) {
82c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
83c63f63a2SAndrew Jeffery 	}
84c63f63a2SAndrew Jeffery 
85c63f63a2SAndrew Jeffery 	return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
86c63f63a2SAndrew Jeffery }
87c63f63a2SAndrew Jeffery 
88c63f63a2SAndrew Jeffery /**
89db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
90db7b8324SAndrew Jeffery  *
91db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
92db7b8324SAndrew Jeffery  *
93db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
94db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
95db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
96db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
97db7b8324SAndrew Jeffery  * pointer.
98db7b8324SAndrew Jeffery  */
99db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
100db7b8324SAndrew Jeffery {
101db7b8324SAndrew Jeffery 	if (!ctx) {
102db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
103db7b8324SAndrew Jeffery 	}
104db7b8324SAndrew Jeffery 
105db7b8324SAndrew Jeffery 	return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
106db7b8324SAndrew Jeffery }
107db7b8324SAndrew Jeffery 
108db7b8324SAndrew Jeffery /**
109c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
110c63f63a2SAndrew Jeffery  *
111c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
112c63f63a2SAndrew Jeffery  *
113c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
114c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
115c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
116c63f63a2SAndrew Jeffery  * bounds of the buffer.
117c63f63a2SAndrew Jeffery  */
118c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
119c63f63a2SAndrew Jeffery {
120c63f63a2SAndrew Jeffery 	int valid;
121c63f63a2SAndrew Jeffery 
122c63f63a2SAndrew Jeffery 	if (!ctx) {
123c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
124c63f63a2SAndrew Jeffery 	}
125c63f63a2SAndrew Jeffery 
126c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
127c63f63a2SAndrew Jeffery 
128c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
129c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
130c63f63a2SAndrew Jeffery 
131c63f63a2SAndrew Jeffery 	return valid;
132c63f63a2SAndrew Jeffery }
133c63f63a2SAndrew Jeffery 
134c63f63a2SAndrew Jeffery /**
135db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
136db7b8324SAndrew Jeffery  * has been completely consumed without overflow
137db7b8324SAndrew Jeffery  *
138db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
139db7b8324SAndrew Jeffery  *
140db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
141db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
142db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
143db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
144db7b8324SAndrew Jeffery  */
145db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
146db7b8324SAndrew Jeffery {
147db7b8324SAndrew Jeffery 	int consumed;
148db7b8324SAndrew Jeffery 
149db7b8324SAndrew Jeffery 	if (!ctx) {
150db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
151db7b8324SAndrew Jeffery 	}
152db7b8324SAndrew Jeffery 
153db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
154db7b8324SAndrew Jeffery 
155db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
156db7b8324SAndrew Jeffery 	ctx->remaining = 0;
157db7b8324SAndrew Jeffery 
158db7b8324SAndrew Jeffery 	return consumed;
159db7b8324SAndrew Jeffery }
160db7b8324SAndrew Jeffery 
161db7b8324SAndrew Jeffery /**
162c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
163c63f63a2SAndrew Jeffery  *
164c63f63a2SAndrew Jeffery  * @param[inout] ctx - pldm_msgbuf context for extractor
165c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
166c63f63a2SAndrew Jeffery  *
167c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
168c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
169c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
170c63f63a2SAndrew Jeffery  */
171c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx,
172c63f63a2SAndrew Jeffery 					    uint8_t *dst)
173c63f63a2SAndrew Jeffery {
174c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
175c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
176c63f63a2SAndrew Jeffery 	}
177c63f63a2SAndrew Jeffery 
178c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
179c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
180c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
181c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
182c63f63a2SAndrew Jeffery 	}
183c63f63a2SAndrew Jeffery 
184c63f63a2SAndrew Jeffery 	*dst = *((uint8_t *)(ctx->cursor));
185c63f63a2SAndrew Jeffery 	ctx->cursor++;
186c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
187c63f63a2SAndrew Jeffery }
188c63f63a2SAndrew Jeffery 
189c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst)
190c63f63a2SAndrew Jeffery {
191c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
192c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
193c63f63a2SAndrew Jeffery 	}
194c63f63a2SAndrew Jeffery 
195c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
196c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
197c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
198c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
199c63f63a2SAndrew Jeffery 	}
200c63f63a2SAndrew Jeffery 
201c63f63a2SAndrew Jeffery 	*dst = *((int8_t *)(ctx->cursor));
202c63f63a2SAndrew Jeffery 	ctx->cursor++;
203c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
204c63f63a2SAndrew Jeffery }
205c63f63a2SAndrew Jeffery 
206c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx,
207c63f63a2SAndrew Jeffery 					     uint16_t *dst)
208c63f63a2SAndrew Jeffery {
209c63f63a2SAndrew Jeffery 	uint16_t ldst;
210c63f63a2SAndrew Jeffery 
211c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
212c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
213c63f63a2SAndrew Jeffery 	}
214c63f63a2SAndrew Jeffery 
215c63f63a2SAndrew Jeffery 	// Check for buffer overflow. If we overflow, account for the request as
216c63f63a2SAndrew Jeffery 	// negative values in ctx->remaining. This way we can debug how far
217c63f63a2SAndrew Jeffery 	// we've overflowed.
218c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
219c63f63a2SAndrew Jeffery 
220c63f63a2SAndrew Jeffery 	// Prevent the access if it would overflow. First, assert so we blow up
221c63f63a2SAndrew Jeffery 	// the test suite right at the point of failure. However, cater to
222c63f63a2SAndrew Jeffery 	// -DNDEBUG by explicitly testing that the access is valid.
223c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
224c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
225c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
226c63f63a2SAndrew Jeffery 	}
227c63f63a2SAndrew Jeffery 
228c63f63a2SAndrew Jeffery 	// Use memcpy() to have the compiler deal with any alignment
229c63f63a2SAndrew Jeffery 	// issues on the target architecture
230c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
231c63f63a2SAndrew Jeffery 
232c63f63a2SAndrew Jeffery 	// Only assign the target value once it's correctly decoded
233c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
234c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
235c63f63a2SAndrew Jeffery 
236c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
237c63f63a2SAndrew Jeffery }
238c63f63a2SAndrew Jeffery 
239c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx,
240c63f63a2SAndrew Jeffery 					    int16_t *dst)
241c63f63a2SAndrew Jeffery {
242c63f63a2SAndrew Jeffery 	int16_t ldst;
243c63f63a2SAndrew Jeffery 
244c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
245c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
246c63f63a2SAndrew Jeffery 	}
247c63f63a2SAndrew Jeffery 
248c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
249c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
250c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
251c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
252c63f63a2SAndrew Jeffery 	}
253c63f63a2SAndrew Jeffery 
254c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
255c63f63a2SAndrew Jeffery 
256c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
257c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
258c63f63a2SAndrew Jeffery 
259c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
260c63f63a2SAndrew Jeffery }
261c63f63a2SAndrew Jeffery 
262c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx,
263c63f63a2SAndrew Jeffery 					     uint32_t *dst)
264c63f63a2SAndrew Jeffery {
265c63f63a2SAndrew Jeffery 	uint32_t ldst;
266c63f63a2SAndrew Jeffery 
267c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
268c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
269c63f63a2SAndrew Jeffery 	}
270c63f63a2SAndrew Jeffery 
271c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
272c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
273c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
274c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
275c63f63a2SAndrew Jeffery 	}
276c63f63a2SAndrew Jeffery 
277c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
278c63f63a2SAndrew Jeffery 
279c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
280c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
281c63f63a2SAndrew Jeffery 
282c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
283c63f63a2SAndrew Jeffery }
284c63f63a2SAndrew Jeffery 
285c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx,
286c63f63a2SAndrew Jeffery 					    int32_t *dst)
287c63f63a2SAndrew Jeffery {
288c63f63a2SAndrew Jeffery 	int32_t ldst;
289c63f63a2SAndrew Jeffery 
290c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
291c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
292c63f63a2SAndrew Jeffery 	}
293c63f63a2SAndrew Jeffery 
294c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
295c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
296c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
297c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
298c63f63a2SAndrew Jeffery 	}
299c63f63a2SAndrew Jeffery 
300c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
301c63f63a2SAndrew Jeffery 
302c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
303c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
304c63f63a2SAndrew Jeffery 
305c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
306c63f63a2SAndrew Jeffery }
307c63f63a2SAndrew Jeffery 
308c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx,
309c63f63a2SAndrew Jeffery 					     real32_t *dst)
310c63f63a2SAndrew Jeffery {
311c63f63a2SAndrew Jeffery 	uint32_t ldst;
312c63f63a2SAndrew Jeffery 
313c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
314c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
315c63f63a2SAndrew Jeffery 	}
316c63f63a2SAndrew Jeffery 
317c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
318c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
319c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
320c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
321c63f63a2SAndrew Jeffery 	}
322c63f63a2SAndrew Jeffery 
323c63f63a2SAndrew Jeffery 	_Static_assert(sizeof(*dst) == sizeof(ldst),
324c63f63a2SAndrew Jeffery 		       "Mismatched type sizes for dst and ldst");
325c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
326c63f63a2SAndrew Jeffery 	ldst = le32toh(ldst);
327c63f63a2SAndrew Jeffery 	memcpy(dst, &ldst, sizeof(*dst));
328c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(*dst);
329c63f63a2SAndrew Jeffery 
330c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
331c63f63a2SAndrew Jeffery }
332c63f63a2SAndrew Jeffery 
333c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
33437dd6a3dSAndrew Jeffery 	_Generic((*(dst)),                                                     \
33537dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_extract_uint8,                            \
33637dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_extract_int8,                              \
33737dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_extract_uint16,                          \
33837dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_extract_int16,                            \
33937dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_extract_uint32,                          \
34037dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_extract_int32,                            \
34137dd6a3dSAndrew Jeffery 		real32_t: pldm_msgbuf_extract_real32)(ctx, dst)
342c63f63a2SAndrew Jeffery 
343369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx,
344369b121aSAndrew Jeffery 						  uint8_t *dst, size_t count)
345369b121aSAndrew Jeffery {
346369b121aSAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
347369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
348369b121aSAndrew Jeffery 	}
349369b121aSAndrew Jeffery 
350369b121aSAndrew Jeffery 	if (!count) {
351369b121aSAndrew Jeffery 		return PLDM_SUCCESS;
352369b121aSAndrew Jeffery 	}
353369b121aSAndrew Jeffery 
354*a065eccbSAndrew Jeffery 	if (count >= SSIZE_MAX) {
355369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
356369b121aSAndrew Jeffery 	}
357369b121aSAndrew Jeffery 
358*a065eccbSAndrew Jeffery 	ctx->remaining -= (ssize_t)count;
359369b121aSAndrew Jeffery 	assert(ctx->remaining >= 0);
360369b121aSAndrew Jeffery 	if (ctx->remaining < 0) {
361369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
362369b121aSAndrew Jeffery 	}
363369b121aSAndrew Jeffery 
364*a065eccbSAndrew Jeffery 	memcpy(dst, ctx->cursor, count);
365*a065eccbSAndrew Jeffery 	ctx->cursor += count;
366369b121aSAndrew Jeffery 
367369b121aSAndrew Jeffery 	return PLDM_SUCCESS;
368369b121aSAndrew Jeffery }
369369b121aSAndrew Jeffery 
370369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
37137dd6a3dSAndrew Jeffery 	_Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
37237dd6a3dSAndrew Jeffery 								     count)
373369b121aSAndrew Jeffery 
374062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
375062c8762SThu Nguyen 					    const uint32_t src)
376062c8762SThu Nguyen {
377062c8762SThu Nguyen 	uint32_t val = htole32(src);
378062c8762SThu Nguyen 
379062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
380062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
381062c8762SThu Nguyen 	}
382062c8762SThu Nguyen 
383062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
384062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
385062c8762SThu Nguyen 	if (ctx->remaining < 0) {
386062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
387062c8762SThu Nguyen 	}
388062c8762SThu Nguyen 
389062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
390062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
391062c8762SThu Nguyen 
392062c8762SThu Nguyen 	return PLDM_SUCCESS;
393062c8762SThu Nguyen }
394062c8762SThu Nguyen 
395062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
396062c8762SThu Nguyen 					    const uint16_t src)
397062c8762SThu Nguyen {
398062c8762SThu Nguyen 	uint16_t val = htole16(src);
399062c8762SThu Nguyen 
400062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
401062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
402062c8762SThu Nguyen 	}
403062c8762SThu Nguyen 
404062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
405062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
406062c8762SThu Nguyen 	if (ctx->remaining < 0) {
407062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
408062c8762SThu Nguyen 	}
409062c8762SThu Nguyen 
410062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
411062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
412062c8762SThu Nguyen 
413062c8762SThu Nguyen 	return PLDM_SUCCESS;
414062c8762SThu Nguyen }
415062c8762SThu Nguyen 
416062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
417062c8762SThu Nguyen 					   const uint8_t src)
418062c8762SThu Nguyen {
419062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
420062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
421062c8762SThu Nguyen 	}
422062c8762SThu Nguyen 
423062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
424062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
425062c8762SThu Nguyen 	if (ctx->remaining < 0) {
426062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
427062c8762SThu Nguyen 	}
428062c8762SThu Nguyen 
429062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
430062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
431062c8762SThu Nguyen 
432062c8762SThu Nguyen 	return PLDM_SUCCESS;
433062c8762SThu Nguyen }
434062c8762SThu Nguyen 
435062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
436062c8762SThu Nguyen 					   const int32_t src)
437062c8762SThu Nguyen {
438062c8762SThu Nguyen 	int32_t val = htole32(src);
439062c8762SThu Nguyen 
440062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
441062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
442062c8762SThu Nguyen 	}
443062c8762SThu Nguyen 
444062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
445062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
446062c8762SThu Nguyen 	if (ctx->remaining < 0) {
447062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
448062c8762SThu Nguyen 	}
449062c8762SThu Nguyen 
450062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
451062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
452062c8762SThu Nguyen 
453062c8762SThu Nguyen 	return PLDM_SUCCESS;
454062c8762SThu Nguyen }
455062c8762SThu Nguyen 
456062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
457062c8762SThu Nguyen 					   const int16_t src)
458062c8762SThu Nguyen {
459062c8762SThu Nguyen 	int16_t val = htole16(src);
460062c8762SThu Nguyen 
461062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
462062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
463062c8762SThu Nguyen 	}
464062c8762SThu Nguyen 
465062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
466062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
467062c8762SThu Nguyen 	if (ctx->remaining < 0) {
468062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
469062c8762SThu Nguyen 	}
470062c8762SThu Nguyen 
471062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
472062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
473062c8762SThu Nguyen 
474062c8762SThu Nguyen 	return PLDM_SUCCESS;
475062c8762SThu Nguyen }
476062c8762SThu Nguyen 
477062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
478062c8762SThu Nguyen 					  const int8_t src)
479062c8762SThu Nguyen {
480062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
481062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
482062c8762SThu Nguyen 	}
483062c8762SThu Nguyen 
484062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
485062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
486062c8762SThu Nguyen 	if (ctx->remaining < 0) {
487062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
488062c8762SThu Nguyen 	}
489062c8762SThu Nguyen 
490062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
491062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
492062c8762SThu Nguyen 
493062c8762SThu Nguyen 	return PLDM_SUCCESS;
494062c8762SThu Nguyen }
495062c8762SThu Nguyen 
496062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
49737dd6a3dSAndrew Jeffery 	_Generic((src),                                                        \
49837dd6a3dSAndrew Jeffery 		uint8_t: pldm_msgbuf_insert_uint8,                             \
49937dd6a3dSAndrew Jeffery 		int8_t: pldm_msgbuf_insert_int8,                               \
50037dd6a3dSAndrew Jeffery 		uint16_t: pldm_msgbuf_insert_uint16,                           \
50137dd6a3dSAndrew Jeffery 		int16_t: pldm_msgbuf_insert_int16,                             \
50237dd6a3dSAndrew Jeffery 		uint32_t: pldm_msgbuf_insert_uint32,                           \
50337dd6a3dSAndrew Jeffery 		int32_t: pldm_msgbuf_insert_int32)(dst, src)
504062c8762SThu Nguyen 
505062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx,
506062c8762SThu Nguyen 						 const uint8_t *src,
507062c8762SThu Nguyen 						 size_t count)
508062c8762SThu Nguyen {
509062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !src) {
510062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
511062c8762SThu Nguyen 	}
512062c8762SThu Nguyen 
513062c8762SThu Nguyen 	if (!count) {
514062c8762SThu Nguyen 		return PLDM_SUCCESS;
515062c8762SThu Nguyen 	}
516062c8762SThu Nguyen 
517*a065eccbSAndrew Jeffery 	if (count >= SSIZE_MAX) {
518062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
519062c8762SThu Nguyen 	}
520062c8762SThu Nguyen 
521*a065eccbSAndrew Jeffery 	ctx->remaining -= (ssize_t)count;
522062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
523062c8762SThu Nguyen 	if (ctx->remaining < 0) {
524062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
525062c8762SThu Nguyen 	}
526062c8762SThu Nguyen 
527*a065eccbSAndrew Jeffery 	memcpy(ctx->cursor, src, count);
528*a065eccbSAndrew Jeffery 	ctx->cursor += count;
529062c8762SThu Nguyen 
530062c8762SThu Nguyen 	return PLDM_SUCCESS;
531062c8762SThu Nguyen }
532062c8762SThu Nguyen 
533062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count)                              \
53437dd6a3dSAndrew Jeffery 	_Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src,  \
53537dd6a3dSAndrew Jeffery 								    count)
536062c8762SThu Nguyen 
537062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
538062c8762SThu Nguyen 					    size_t required, void **cursor)
539062c8762SThu Nguyen {
540062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor) {
541062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
542062c8762SThu Nguyen 	}
543062c8762SThu Nguyen 
544062c8762SThu Nguyen 	if (required > SSIZE_MAX) {
545062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
546062c8762SThu Nguyen 	}
547062c8762SThu Nguyen 
548062c8762SThu Nguyen 	ctx->remaining -= (ssize_t)required;
549062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
550062c8762SThu Nguyen 	if (ctx->remaining < 0) {
551062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
552062c8762SThu Nguyen 	}
553062c8762SThu Nguyen 
554062c8762SThu Nguyen 	*cursor = ctx->cursor;
555062c8762SThu Nguyen 	ctx->cursor += required;
556062c8762SThu Nguyen 
557062c8762SThu Nguyen 	return PLDM_SUCCESS;
558062c8762SThu Nguyen }
559062c8762SThu Nguyen 
560062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx,
561062c8762SThu Nguyen 					     void **cursor, size_t *len)
562062c8762SThu Nguyen {
563062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
564062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
565062c8762SThu Nguyen 	}
566062c8762SThu Nguyen 
567062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
568062c8762SThu Nguyen 	if (ctx->remaining < 0) {
569062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
570062c8762SThu Nguyen 	}
571062c8762SThu Nguyen 
572062c8762SThu Nguyen 	*cursor = ctx->cursor;
573062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
574062c8762SThu Nguyen 	*len = ctx->remaining;
575062c8762SThu Nguyen 	ctx->remaining = 0;
576062c8762SThu Nguyen 
577062c8762SThu Nguyen 	return PLDM_SUCCESS;
578062c8762SThu Nguyen }
579c63f63a2SAndrew Jeffery #ifdef __cplusplus
580c63f63a2SAndrew Jeffery }
581c63f63a2SAndrew Jeffery #endif
582c63f63a2SAndrew Jeffery 
583c63f63a2SAndrew Jeffery #endif /* BUF_H */
584