xref: /openbmc/libpldm/src/msgbuf.h (revision 062c8762)
1c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H
2c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H
3c63f63a2SAndrew Jeffery 
4c63f63a2SAndrew Jeffery #ifdef __cplusplus
5c63f63a2SAndrew Jeffery extern "C" {
6c63f63a2SAndrew Jeffery #endif
7c63f63a2SAndrew Jeffery 
8c63f63a2SAndrew Jeffery #include "base.h"
9c63f63a2SAndrew Jeffery #include "pldm_types.h"
10c63f63a2SAndrew Jeffery 
11c63f63a2SAndrew Jeffery #include <assert.h>
12c63f63a2SAndrew Jeffery #include <endian.h>
13c63f63a2SAndrew Jeffery #include <limits.h>
14c63f63a2SAndrew Jeffery #include <stdbool.h>
15c63f63a2SAndrew Jeffery #include <string.h>
16c63f63a2SAndrew Jeffery #include <sys/types.h>
17c63f63a2SAndrew Jeffery 
18*062c8762SThu Nguyen /*
19*062c8762SThu Nguyen  * Fix up C11's _Static_assert() vs C++'s static_assert().
20*062c8762SThu Nguyen  *
21*062c8762SThu Nguyen  * Can we please have nice things for once.
22*062c8762SThu Nguyen  */
23*062c8762SThu Nguyen #ifdef __cplusplus
24*062c8762SThu Nguyen // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
25*062c8762SThu Nguyen #define _Static_assert(...) static_assert(__VA_ARGS__)
26*062c8762SThu Nguyen #endif
27*062c8762SThu Nguyen 
28c63f63a2SAndrew Jeffery struct pldm_msgbuf {
29*062c8762SThu Nguyen 	uint8_t *cursor;
30c63f63a2SAndrew Jeffery 	ssize_t remaining;
31c63f63a2SAndrew Jeffery };
32c63f63a2SAndrew Jeffery 
33c63f63a2SAndrew Jeffery /**
34c63f63a2SAndrew Jeffery  * @brief Initialize pldm buf struct for buf extractor
35c63f63a2SAndrew Jeffery  *
36c63f63a2SAndrew Jeffery  * @param[out] ctx - pldm_msgbuf context for extractor
37c63f63a2SAndrew Jeffery  * @param[in] minsize - The minimum required length of buffer `buf`
38c63f63a2SAndrew Jeffery  * @param[in] buf - buffer to be extracted
39c63f63a2SAndrew Jeffery  * @param[in] len - size of buffer
40c63f63a2SAndrew Jeffery  *
41c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
42c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or
43c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
44c63f63a2SAndrew Jeffery  */
455646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int
465646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
475646f23bSAndrew Jeffery 		 size_t len)
48c63f63a2SAndrew Jeffery {
49c63f63a2SAndrew Jeffery 	uint8_t *end;
50c63f63a2SAndrew Jeffery 
51c63f63a2SAndrew Jeffery 	if (!ctx || !buf) {
52c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
53c63f63a2SAndrew Jeffery 	}
54c63f63a2SAndrew Jeffery 
55c63f63a2SAndrew Jeffery 	if ((minsize > len) || (len > SSIZE_MAX)) {
56c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
57c63f63a2SAndrew Jeffery 	}
58c63f63a2SAndrew Jeffery 
59c63f63a2SAndrew Jeffery 	end = (uint8_t *)buf + len;
60c63f63a2SAndrew Jeffery 	if (end && end < (uint8_t *)buf) {
61c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
62c63f63a2SAndrew Jeffery 	}
63c63f63a2SAndrew Jeffery 
64c63f63a2SAndrew Jeffery 	ctx->cursor = (uint8_t *)buf;
65c63f63a2SAndrew Jeffery 	ctx->remaining = (ssize_t)len;
66c63f63a2SAndrew Jeffery 
67c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
68c63f63a2SAndrew Jeffery }
69c63f63a2SAndrew Jeffery 
70c63f63a2SAndrew Jeffery /**
71c63f63a2SAndrew Jeffery  * @brief Validate buffer overflow state
72c63f63a2SAndrew Jeffery  *
73c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
74c63f63a2SAndrew Jeffery  *
75c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
76c63f63a2SAndrew Jeffery  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
77c63f63a2SAndrew Jeffery  * prior accesses would have occurred beyond the bounds of the buffer, and
78c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
79c63f63a2SAndrew Jeffery  * pointer.
80c63f63a2SAndrew Jeffery  */
81c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
82c63f63a2SAndrew Jeffery {
83c63f63a2SAndrew Jeffery 	if (!ctx) {
84c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
85c63f63a2SAndrew Jeffery 	}
86c63f63a2SAndrew Jeffery 
87c63f63a2SAndrew Jeffery 	return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
88c63f63a2SAndrew Jeffery }
89c63f63a2SAndrew Jeffery 
90c63f63a2SAndrew Jeffery /**
91db7b8324SAndrew Jeffery  * @brief Test whether a message buffer has been exactly consumed
92db7b8324SAndrew Jeffery  *
93db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
94db7b8324SAndrew Jeffery  *
95db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
96db7b8324SAndrew Jeffery  * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
97db7b8324SAndrew Jeffery  * indicates that an incorrect sequence of accesses have occurred, and
98db7b8324SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
99db7b8324SAndrew Jeffery  * pointer.
100db7b8324SAndrew Jeffery  */
101db7b8324SAndrew Jeffery static inline int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
102db7b8324SAndrew Jeffery {
103db7b8324SAndrew Jeffery 	if (!ctx) {
104db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
105db7b8324SAndrew Jeffery 	}
106db7b8324SAndrew Jeffery 
107db7b8324SAndrew Jeffery 	return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
108db7b8324SAndrew Jeffery }
109db7b8324SAndrew Jeffery 
110db7b8324SAndrew Jeffery /**
111c63f63a2SAndrew Jeffery  * @brief Destroy the pldm buf
112c63f63a2SAndrew Jeffery  *
113c63f63a2SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context for extractor
114c63f63a2SAndrew Jeffery  *
115c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
116c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
117c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
118c63f63a2SAndrew Jeffery  * bounds of the buffer.
119c63f63a2SAndrew Jeffery  */
120c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
121c63f63a2SAndrew Jeffery {
122c63f63a2SAndrew Jeffery 	int valid;
123c63f63a2SAndrew Jeffery 
124c63f63a2SAndrew Jeffery 	if (!ctx) {
125c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
126c63f63a2SAndrew Jeffery 	}
127c63f63a2SAndrew Jeffery 
128c63f63a2SAndrew Jeffery 	valid = pldm_msgbuf_validate(ctx);
129c63f63a2SAndrew Jeffery 
130c63f63a2SAndrew Jeffery 	ctx->cursor = NULL;
131c63f63a2SAndrew Jeffery 	ctx->remaining = 0;
132c63f63a2SAndrew Jeffery 
133c63f63a2SAndrew Jeffery 	return valid;
134c63f63a2SAndrew Jeffery }
135c63f63a2SAndrew Jeffery 
136c63f63a2SAndrew Jeffery /**
137db7b8324SAndrew Jeffery  * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
138db7b8324SAndrew Jeffery  * has been completely consumed without overflow
139db7b8324SAndrew Jeffery  *
140db7b8324SAndrew Jeffery  * @param[in] ctx - pldm_msgbuf context
141db7b8324SAndrew Jeffery  *
142db7b8324SAndrew Jeffery  * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
143db7b8324SAndrew Jeffery  * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
144db7b8324SAndrew Jeffery  * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
145db7b8324SAndrew Jeffery  * have occurred byond the bounds of the buffer
146db7b8324SAndrew Jeffery  */
147db7b8324SAndrew Jeffery static inline int pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
148db7b8324SAndrew Jeffery {
149db7b8324SAndrew Jeffery 	int consumed;
150db7b8324SAndrew Jeffery 
151db7b8324SAndrew Jeffery 	if (!ctx) {
152db7b8324SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
153db7b8324SAndrew Jeffery 	}
154db7b8324SAndrew Jeffery 
155db7b8324SAndrew Jeffery 	consumed = pldm_msgbuf_consumed(ctx);
156db7b8324SAndrew Jeffery 
157db7b8324SAndrew Jeffery 	ctx->cursor = NULL;
158db7b8324SAndrew Jeffery 	ctx->remaining = 0;
159db7b8324SAndrew Jeffery 
160db7b8324SAndrew Jeffery 	return consumed;
161db7b8324SAndrew Jeffery }
162db7b8324SAndrew Jeffery 
163db7b8324SAndrew Jeffery /**
164c63f63a2SAndrew Jeffery  * @brief pldm_msgbuf extractor for a uint8_t
165c63f63a2SAndrew Jeffery  *
166c63f63a2SAndrew Jeffery  * @param[inout] ctx - pldm_msgbuf context for extractor
167c63f63a2SAndrew Jeffery  * @param[out] dst - destination of extracted value
168c63f63a2SAndrew Jeffery  *
169c63f63a2SAndrew Jeffery  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
170c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_LENGTH otherwise.
171c63f63a2SAndrew Jeffery  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
172c63f63a2SAndrew Jeffery  */
173c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx,
174c63f63a2SAndrew Jeffery 					    uint8_t *dst)
175c63f63a2SAndrew Jeffery {
176c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
177c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
178c63f63a2SAndrew Jeffery 	}
179c63f63a2SAndrew Jeffery 
180c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
181c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
182c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
183c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
184c63f63a2SAndrew Jeffery 	}
185c63f63a2SAndrew Jeffery 
186c63f63a2SAndrew Jeffery 	*dst = *((uint8_t *)(ctx->cursor));
187c63f63a2SAndrew Jeffery 	ctx->cursor++;
188c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
189c63f63a2SAndrew Jeffery }
190c63f63a2SAndrew Jeffery 
191c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst)
192c63f63a2SAndrew Jeffery {
193c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
194c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
195c63f63a2SAndrew Jeffery 	}
196c63f63a2SAndrew Jeffery 
197c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(*dst);
198c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
199c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
200c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
201c63f63a2SAndrew Jeffery 	}
202c63f63a2SAndrew Jeffery 
203c63f63a2SAndrew Jeffery 	*dst = *((int8_t *)(ctx->cursor));
204c63f63a2SAndrew Jeffery 	ctx->cursor++;
205c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
206c63f63a2SAndrew Jeffery }
207c63f63a2SAndrew Jeffery 
208c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx,
209c63f63a2SAndrew Jeffery 					     uint16_t *dst)
210c63f63a2SAndrew Jeffery {
211c63f63a2SAndrew Jeffery 	uint16_t ldst;
212c63f63a2SAndrew Jeffery 
213c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
214c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
215c63f63a2SAndrew Jeffery 	}
216c63f63a2SAndrew Jeffery 
217c63f63a2SAndrew Jeffery 	// Check for buffer overflow. If we overflow, account for the request as
218c63f63a2SAndrew Jeffery 	// negative values in ctx->remaining. This way we can debug how far
219c63f63a2SAndrew Jeffery 	// we've overflowed.
220c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
221c63f63a2SAndrew Jeffery 
222c63f63a2SAndrew Jeffery 	// Prevent the access if it would overflow. First, assert so we blow up
223c63f63a2SAndrew Jeffery 	// the test suite right at the point of failure. However, cater to
224c63f63a2SAndrew Jeffery 	// -DNDEBUG by explicitly testing that the access is valid.
225c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
226c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
227c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
228c63f63a2SAndrew Jeffery 	}
229c63f63a2SAndrew Jeffery 
230c63f63a2SAndrew Jeffery 	// Use memcpy() to have the compiler deal with any alignment
231c63f63a2SAndrew Jeffery 	// issues on the target architecture
232c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
233c63f63a2SAndrew Jeffery 
234c63f63a2SAndrew Jeffery 	// Only assign the target value once it's correctly decoded
235c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
236c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
237c63f63a2SAndrew Jeffery 
238c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
239c63f63a2SAndrew Jeffery }
240c63f63a2SAndrew Jeffery 
241c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx,
242c63f63a2SAndrew Jeffery 					    int16_t *dst)
243c63f63a2SAndrew Jeffery {
244c63f63a2SAndrew Jeffery 	int16_t ldst;
245c63f63a2SAndrew Jeffery 
246c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
247c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
248c63f63a2SAndrew Jeffery 	}
249c63f63a2SAndrew Jeffery 
250c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
251c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
252c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
253c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
254c63f63a2SAndrew Jeffery 	}
255c63f63a2SAndrew Jeffery 
256c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
257c63f63a2SAndrew Jeffery 
258c63f63a2SAndrew Jeffery 	*dst = le16toh(ldst);
259c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
260c63f63a2SAndrew Jeffery 
261c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
262c63f63a2SAndrew Jeffery }
263c63f63a2SAndrew Jeffery 
264c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx,
265c63f63a2SAndrew Jeffery 					     uint32_t *dst)
266c63f63a2SAndrew Jeffery {
267c63f63a2SAndrew Jeffery 	uint32_t ldst;
268c63f63a2SAndrew Jeffery 
269c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
270c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
271c63f63a2SAndrew Jeffery 	}
272c63f63a2SAndrew Jeffery 
273c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
274c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
275c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
276c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
277c63f63a2SAndrew Jeffery 	}
278c63f63a2SAndrew Jeffery 
279c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
280c63f63a2SAndrew Jeffery 
281c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
282c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
283c63f63a2SAndrew Jeffery 
284c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
285c63f63a2SAndrew Jeffery }
286c63f63a2SAndrew Jeffery 
287c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx,
288c63f63a2SAndrew Jeffery 					    int32_t *dst)
289c63f63a2SAndrew Jeffery {
290c63f63a2SAndrew Jeffery 	int32_t ldst;
291c63f63a2SAndrew Jeffery 
292c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
293c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
294c63f63a2SAndrew Jeffery 	}
295c63f63a2SAndrew Jeffery 
296c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
297c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
298c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
299c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
300c63f63a2SAndrew Jeffery 	}
301c63f63a2SAndrew Jeffery 
302c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
303c63f63a2SAndrew Jeffery 
304c63f63a2SAndrew Jeffery 	*dst = le32toh(ldst);
305c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(ldst);
306c63f63a2SAndrew Jeffery 
307c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
308c63f63a2SAndrew Jeffery }
309c63f63a2SAndrew Jeffery 
310c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx,
311c63f63a2SAndrew Jeffery 					     real32_t *dst)
312c63f63a2SAndrew Jeffery {
313c63f63a2SAndrew Jeffery 	uint32_t ldst;
314c63f63a2SAndrew Jeffery 
315c63f63a2SAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
316c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
317c63f63a2SAndrew Jeffery 	}
318c63f63a2SAndrew Jeffery 
319c63f63a2SAndrew Jeffery 	ctx->remaining -= sizeof(ldst);
320c63f63a2SAndrew Jeffery 	assert(ctx->remaining >= 0);
321c63f63a2SAndrew Jeffery 	if (ctx->remaining < 0) {
322c63f63a2SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
323c63f63a2SAndrew Jeffery 	}
324c63f63a2SAndrew Jeffery 
325c63f63a2SAndrew Jeffery 	_Static_assert(sizeof(*dst) == sizeof(ldst),
326c63f63a2SAndrew Jeffery 		       "Mismatched type sizes for dst and ldst");
327c63f63a2SAndrew Jeffery 	memcpy(&ldst, ctx->cursor, sizeof(ldst));
328c63f63a2SAndrew Jeffery 	ldst = le32toh(ldst);
329c63f63a2SAndrew Jeffery 	memcpy(dst, &ldst, sizeof(*dst));
330c63f63a2SAndrew Jeffery 	ctx->cursor += sizeof(*dst);
331c63f63a2SAndrew Jeffery 
332c63f63a2SAndrew Jeffery 	return PLDM_SUCCESS;
333c63f63a2SAndrew Jeffery }
334c63f63a2SAndrew Jeffery 
335c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst)                                          \
336c63f63a2SAndrew Jeffery 	_Generic((*(dst)), uint8_t                                             \
337c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_uint8, int8_t                           \
338c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_int8, uint16_t                          \
339c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_uint16, int16_t                         \
340c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_int16, uint32_t                         \
341c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_uint32, int32_t                         \
342c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_int32, real32_t                         \
343c63f63a2SAndrew Jeffery 		 : pldm_msgbuf_extract_real32)(ctx, dst)
344c63f63a2SAndrew Jeffery 
345369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx,
346369b121aSAndrew Jeffery 						  uint8_t *dst, size_t count)
347369b121aSAndrew Jeffery {
348369b121aSAndrew Jeffery 	size_t len;
349369b121aSAndrew Jeffery 
350369b121aSAndrew Jeffery 	if (!ctx || !ctx->cursor || !dst) {
351369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
352369b121aSAndrew Jeffery 	}
353369b121aSAndrew Jeffery 
354369b121aSAndrew Jeffery 	if (!count) {
355369b121aSAndrew Jeffery 		return PLDM_SUCCESS;
356369b121aSAndrew Jeffery 	}
357369b121aSAndrew Jeffery 
358369b121aSAndrew Jeffery 	len = sizeof(*dst) * count;
359369b121aSAndrew Jeffery 	if (len > SSIZE_MAX) {
360369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
361369b121aSAndrew Jeffery 	}
362369b121aSAndrew Jeffery 
363369b121aSAndrew Jeffery 	ctx->remaining -= (ssize_t)len;
364369b121aSAndrew Jeffery 	assert(ctx->remaining >= 0);
365369b121aSAndrew Jeffery 	if (ctx->remaining < 0) {
366369b121aSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
367369b121aSAndrew Jeffery 	}
368369b121aSAndrew Jeffery 
369369b121aSAndrew Jeffery 	memcpy(dst, ctx->cursor, len);
370369b121aSAndrew Jeffery 	ctx->cursor += len;
371369b121aSAndrew Jeffery 
372369b121aSAndrew Jeffery 	return PLDM_SUCCESS;
373369b121aSAndrew Jeffery }
374369b121aSAndrew Jeffery 
375369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count)                             \
376369b121aSAndrew Jeffery 	_Generic((*(dst)), uint8_t                                             \
377369b121aSAndrew Jeffery 		 : pldm_msgbuf_extract_array_uint8)(ctx, dst, count)
378369b121aSAndrew Jeffery 
379*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
380*062c8762SThu Nguyen 					    const uint32_t src)
381*062c8762SThu Nguyen {
382*062c8762SThu Nguyen 	uint32_t val = htole32(src);
383*062c8762SThu Nguyen 
384*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
385*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
386*062c8762SThu Nguyen 	}
387*062c8762SThu Nguyen 
388*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
389*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
390*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
391*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
392*062c8762SThu Nguyen 	}
393*062c8762SThu Nguyen 
394*062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
395*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
396*062c8762SThu Nguyen 
397*062c8762SThu Nguyen 	return PLDM_SUCCESS;
398*062c8762SThu Nguyen }
399*062c8762SThu Nguyen 
400*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
401*062c8762SThu Nguyen 					    const uint16_t src)
402*062c8762SThu Nguyen {
403*062c8762SThu Nguyen 	uint16_t val = htole16(src);
404*062c8762SThu Nguyen 
405*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
406*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
407*062c8762SThu Nguyen 	}
408*062c8762SThu Nguyen 
409*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
410*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
411*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
412*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
413*062c8762SThu Nguyen 	}
414*062c8762SThu Nguyen 
415*062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
416*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
417*062c8762SThu Nguyen 
418*062c8762SThu Nguyen 	return PLDM_SUCCESS;
419*062c8762SThu Nguyen }
420*062c8762SThu Nguyen 
421*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
422*062c8762SThu Nguyen 					   const uint8_t src)
423*062c8762SThu Nguyen {
424*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
425*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
426*062c8762SThu Nguyen 	}
427*062c8762SThu Nguyen 
428*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
429*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
430*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
431*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
432*062c8762SThu Nguyen 	}
433*062c8762SThu Nguyen 
434*062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
435*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
436*062c8762SThu Nguyen 
437*062c8762SThu Nguyen 	return PLDM_SUCCESS;
438*062c8762SThu Nguyen }
439*062c8762SThu Nguyen 
440*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
441*062c8762SThu Nguyen 					   const int32_t src)
442*062c8762SThu Nguyen {
443*062c8762SThu Nguyen 	int32_t val = htole32(src);
444*062c8762SThu Nguyen 
445*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
446*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
447*062c8762SThu Nguyen 	}
448*062c8762SThu Nguyen 
449*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
450*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
451*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
452*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
453*062c8762SThu Nguyen 	}
454*062c8762SThu Nguyen 
455*062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
456*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
457*062c8762SThu Nguyen 
458*062c8762SThu Nguyen 	return PLDM_SUCCESS;
459*062c8762SThu Nguyen }
460*062c8762SThu Nguyen 
461*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
462*062c8762SThu Nguyen 					   const int16_t src)
463*062c8762SThu Nguyen {
464*062c8762SThu Nguyen 	int16_t val = htole16(src);
465*062c8762SThu Nguyen 
466*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
467*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
468*062c8762SThu Nguyen 	}
469*062c8762SThu Nguyen 
470*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
471*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
472*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
473*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
474*062c8762SThu Nguyen 	}
475*062c8762SThu Nguyen 
476*062c8762SThu Nguyen 	memcpy(ctx->cursor, &val, sizeof(val));
477*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
478*062c8762SThu Nguyen 
479*062c8762SThu Nguyen 	return PLDM_SUCCESS;
480*062c8762SThu Nguyen }
481*062c8762SThu Nguyen 
482*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
483*062c8762SThu Nguyen 					  const int8_t src)
484*062c8762SThu Nguyen {
485*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor) {
486*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
487*062c8762SThu Nguyen 	}
488*062c8762SThu Nguyen 
489*062c8762SThu Nguyen 	ctx->remaining -= sizeof(src);
490*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
491*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
492*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
493*062c8762SThu Nguyen 	}
494*062c8762SThu Nguyen 
495*062c8762SThu Nguyen 	memcpy(ctx->cursor, &src, sizeof(src));
496*062c8762SThu Nguyen 	ctx->cursor += sizeof(src);
497*062c8762SThu Nguyen 
498*062c8762SThu Nguyen 	return PLDM_SUCCESS;
499*062c8762SThu Nguyen }
500*062c8762SThu Nguyen 
501*062c8762SThu Nguyen #define pldm_msgbuf_insert(dst, src)                                           \
502*062c8762SThu Nguyen 	_Generic((src), uint8_t                                                \
503*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_uint8, int8_t                            \
504*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_int8, uint16_t                           \
505*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_uint16, int16_t                          \
506*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_int16, uint32_t                          \
507*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_uint32, int32_t                          \
508*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_int32)(dst, src)
509*062c8762SThu Nguyen 
510*062c8762SThu Nguyen static inline int pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx,
511*062c8762SThu Nguyen 						 const uint8_t *src,
512*062c8762SThu Nguyen 						 size_t count)
513*062c8762SThu Nguyen {
514*062c8762SThu Nguyen 	size_t len;
515*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !src) {
516*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
517*062c8762SThu Nguyen 	}
518*062c8762SThu Nguyen 
519*062c8762SThu Nguyen 	if (!count) {
520*062c8762SThu Nguyen 		return PLDM_SUCCESS;
521*062c8762SThu Nguyen 	}
522*062c8762SThu Nguyen 
523*062c8762SThu Nguyen 	len = sizeof(*src) * count;
524*062c8762SThu Nguyen 	if (len > SSIZE_MAX) {
525*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
526*062c8762SThu Nguyen 	}
527*062c8762SThu Nguyen 
528*062c8762SThu Nguyen 	ctx->remaining -= (ssize_t)len;
529*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
530*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
531*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
532*062c8762SThu Nguyen 	}
533*062c8762SThu Nguyen 
534*062c8762SThu Nguyen 	memcpy(ctx->cursor, src, len);
535*062c8762SThu Nguyen 	ctx->cursor += len;
536*062c8762SThu Nguyen 
537*062c8762SThu Nguyen 	return PLDM_SUCCESS;
538*062c8762SThu Nguyen }
539*062c8762SThu Nguyen 
540*062c8762SThu Nguyen #define pldm_msgbuf_insert_array(dst, src, count)                              \
541*062c8762SThu Nguyen 	_Generic((*(src)), uint8_t                                             \
542*062c8762SThu Nguyen 		 : pldm_msgbuf_insert_array_uint8)(dst, src, count)
543*062c8762SThu Nguyen 
544*062c8762SThu Nguyen static inline int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
545*062c8762SThu Nguyen 					    size_t required, void **cursor)
546*062c8762SThu Nguyen {
547*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor) {
548*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
549*062c8762SThu Nguyen 	}
550*062c8762SThu Nguyen 
551*062c8762SThu Nguyen 	if (required > SSIZE_MAX) {
552*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
553*062c8762SThu Nguyen 	}
554*062c8762SThu Nguyen 
555*062c8762SThu Nguyen 	ctx->remaining -= (ssize_t)required;
556*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
557*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
558*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
559*062c8762SThu Nguyen 	}
560*062c8762SThu Nguyen 
561*062c8762SThu Nguyen 	*cursor = ctx->cursor;
562*062c8762SThu Nguyen 	ctx->cursor += required;
563*062c8762SThu Nguyen 
564*062c8762SThu Nguyen 	return PLDM_SUCCESS;
565*062c8762SThu Nguyen }
566*062c8762SThu Nguyen 
567*062c8762SThu Nguyen static inline int pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx,
568*062c8762SThu Nguyen 					     void **cursor, size_t *len)
569*062c8762SThu Nguyen {
570*062c8762SThu Nguyen 	if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
571*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_DATA;
572*062c8762SThu Nguyen 	}
573*062c8762SThu Nguyen 
574*062c8762SThu Nguyen 	assert(ctx->remaining >= 0);
575*062c8762SThu Nguyen 	if (ctx->remaining < 0) {
576*062c8762SThu Nguyen 		return PLDM_ERROR_INVALID_LENGTH;
577*062c8762SThu Nguyen 	}
578*062c8762SThu Nguyen 
579*062c8762SThu Nguyen 	*cursor = ctx->cursor;
580*062c8762SThu Nguyen 	ctx->cursor += ctx->remaining;
581*062c8762SThu Nguyen 	*len = ctx->remaining;
582*062c8762SThu Nguyen 	ctx->remaining = 0;
583*062c8762SThu Nguyen 
584*062c8762SThu Nguyen 	return PLDM_SUCCESS;
585*062c8762SThu Nguyen }
586c63f63a2SAndrew Jeffery #ifdef __cplusplus
587c63f63a2SAndrew Jeffery }
588c63f63a2SAndrew Jeffery #endif
589c63f63a2SAndrew Jeffery 
590c63f63a2SAndrew Jeffery #endif /* BUF_H */
591