xref: /openbmc/libpldm/src/dsp/base.c (revision 4e3d5725eb19cef457558dc6da647509d52cfef1)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "api.h"
3 #include "dsp/base.h"
4 #include "msgbuf.h"
5 
6 #include <assert.h>
7 #include <libpldm/base.h>
8 #include <libpldm/pldm_types.h>
9 
10 #include <endian.h>
11 #include <errno.h>
12 #include <limits.h>
13 #include <stdint.h>
14 #include <string.h>
15 
pack_pldm_header_errno(const struct pldm_header_info * hdr,struct pldm_msg_hdr * msg)16 int pack_pldm_header_errno(const struct pldm_header_info *hdr,
17 			   struct pldm_msg_hdr *msg)
18 {
19 	if (msg == NULL || hdr == NULL) {
20 		return -EINVAL;
21 	}
22 
23 	if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST &&
24 	    hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) {
25 		return -EINVAL;
26 	}
27 
28 	if (hdr->instance > PLDM_INSTANCE_MAX) {
29 		return -EINVAL;
30 	}
31 
32 	if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) {
33 		return -ENOMSG;
34 	}
35 
36 	uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0;
37 
38 	if (hdr->msg_type == PLDM_RESPONSE) {
39 		msg->request = PLDM_RESPONSE;
40 	} else if (hdr->msg_type == PLDM_REQUEST ||
41 		   hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) {
42 		msg->request = PLDM_REQUEST;
43 	}
44 	msg->datagram = datagram;
45 	msg->reserved = 0;
46 	msg->instance_id = hdr->instance;
47 	msg->header_ver = PLDM_CURRENT_VERSION;
48 	msg->type = hdr->pldm_type;
49 	msg->command = hdr->command;
50 
51 	return 0;
52 }
53 
unpack_pldm_header_errno(const struct pldm_msg_hdr * msg,struct pldm_header_info * hdr)54 int unpack_pldm_header_errno(const struct pldm_msg_hdr *msg,
55 			     struct pldm_header_info *hdr)
56 {
57 	if (msg == NULL) {
58 		return -EINVAL;
59 	}
60 
61 	if (msg->request == PLDM_RESPONSE) {
62 		hdr->msg_type = PLDM_RESPONSE;
63 	} else {
64 		hdr->msg_type = msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY :
65 						PLDM_REQUEST;
66 	}
67 
68 	hdr->instance = msg->instance_id;
69 	hdr->pldm_type = msg->type;
70 	hdr->command = msg->command;
71 
72 	return 0;
73 }
74 
75 LIBPLDM_ABI_STABLE
pack_pldm_header(const struct pldm_header_info * hdr,struct pldm_msg_hdr * msg)76 uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
77 			 struct pldm_msg_hdr *msg)
78 {
79 	enum pldm_completion_codes cc;
80 	int rc;
81 
82 	rc = pack_pldm_header_errno(hdr, msg);
83 	if (!rc) {
84 		return PLDM_SUCCESS;
85 	}
86 
87 	cc = pldm_xlate_errno(rc);
88 	assert(cc < UINT8_MAX);
89 	if (cc > UINT8_MAX) {
90 		static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error");
91 		return PLDM_ERROR;
92 	}
93 
94 	return cc;
95 }
96 
97 LIBPLDM_ABI_STABLE
unpack_pldm_header(const struct pldm_msg_hdr * msg,struct pldm_header_info * hdr)98 uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
99 			   struct pldm_header_info *hdr)
100 {
101 	enum pldm_completion_codes cc;
102 	int rc;
103 
104 	rc = unpack_pldm_header_errno(msg, hdr);
105 	if (!rc) {
106 		return PLDM_SUCCESS;
107 	}
108 
109 	cc = pldm_xlate_errno(rc);
110 	assert(cc < UINT8_MAX);
111 	if (cc > UINT8_MAX) {
112 		static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error");
113 		return PLDM_ERROR;
114 	}
115 
116 	return cc;
117 }
118 
119 LIBPLDM_ABI_STABLE
pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr * req,const struct pldm_msg_hdr * resp)120 bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req,
121 				     const struct pldm_msg_hdr *resp)
122 {
123 	return req->instance_id == resp->instance_id && req->request &&
124 	       !resp->request && req->type == resp->type &&
125 	       req->command == resp->command;
126 }
127 
128 #define BCD_H(v)       (((v) >> 4) & 0xf)
129 #define BCD_L(v)       ((v) & 0xf)
130 #define AS_CHAR(digit) ((digit) + '0')
131 #define INSERT_CHAR(c, b, n)                                                   \
132 	{                                                                      \
133 		if ((n) > 1) {                                                 \
134 			*(b)++ = (c);                                          \
135 			(n)--;                                                 \
136 		}                                                              \
137 	}
138 #define INSERT_INT(i, b, n) INSERT_CHAR(AS_CHAR(i), (b), (n))
139 
140 LIBPLDM_ABI_STABLE
pldm_base_ver2str(const ver32_t * version,char * buffer,size_t buffer_size)141 ssize_t pldm_base_ver2str(const ver32_t *version, char *buffer,
142 			  size_t buffer_size)
143 {
144 	ssize_t remaining;
145 	char *cursor;
146 
147 	if (!version || !buffer) {
148 		return -1;
149 	}
150 
151 	if (!buffer_size) {
152 		return -1;
153 	}
154 
155 	if (buffer_size > SSIZE_MAX) {
156 		return -1;
157 	}
158 
159 	cursor = buffer;
160 	remaining = (ssize_t)buffer_size;
161 
162 	if (version->major < 0xf0)
163 		INSERT_INT(BCD_H(version->major), cursor, remaining)
164 	INSERT_INT(BCD_L(version->major), cursor, remaining);
165 	INSERT_CHAR('.', cursor, remaining);
166 
167 	if (version->minor < 0xf0)
168 		INSERT_INT(BCD_H(version->minor), cursor, remaining);
169 	INSERT_INT(BCD_L(version->minor), cursor, remaining);
170 
171 	if (version->update < 0xff) {
172 		INSERT_CHAR('.', cursor, remaining);
173 		if (version->update < 0xf0)
174 			INSERT_INT(BCD_H(version->update), cursor, remaining);
175 		INSERT_INT(BCD_L(version->update), cursor, remaining);
176 	}
177 
178 	if (version->alpha)
179 		INSERT_CHAR(version->alpha, cursor, remaining);
180 
181 	*cursor = '\0';
182 
183 	return (ssize_t)buffer_size - remaining;
184 }
185 
186 LIBPLDM_ABI_STABLE
encode_get_types_req(uint8_t instance_id,struct pldm_msg * msg)187 int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
188 {
189 	if (msg == NULL) {
190 		return PLDM_ERROR_INVALID_DATA;
191 	}
192 
193 	struct pldm_header_info header = { 0 };
194 	header.instance = instance_id;
195 	header.msg_type = PLDM_REQUEST;
196 	header.command = PLDM_GET_PLDM_TYPES;
197 
198 	return pack_pldm_header(&header, &(msg->hdr));
199 }
200 
201 LIBPLDM_ABI_STABLE
encode_get_commands_req(uint8_t instance_id,uint8_t type,ver32_t version,struct pldm_msg * msg)202 int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
203 			    struct pldm_msg *msg)
204 {
205 	if (msg == NULL) {
206 		return PLDM_ERROR_INVALID_DATA;
207 	}
208 
209 	struct pldm_header_info header = { 0 };
210 	header.instance = instance_id;
211 	header.msg_type = PLDM_REQUEST;
212 	header.command = PLDM_GET_PLDM_COMMANDS;
213 
214 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
215 	if (rc != PLDM_SUCCESS) {
216 		return rc;
217 	}
218 
219 	struct pldm_get_commands_req *request =
220 		(struct pldm_get_commands_req *)msg->payload;
221 
222 	request->type = type;
223 	request->version = version;
224 
225 	return PLDM_SUCCESS;
226 }
227 
228 LIBPLDM_ABI_STABLE
encode_get_types_resp(uint8_t instance_id,uint8_t completion_code,const bitfield8_t * types,struct pldm_msg * msg)229 int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
230 			  const bitfield8_t *types, struct pldm_msg *msg)
231 {
232 	if (msg == NULL) {
233 		return PLDM_ERROR_INVALID_DATA;
234 	}
235 
236 	struct pldm_header_info header = { 0 };
237 	header.instance = instance_id;
238 	header.msg_type = PLDM_RESPONSE;
239 	header.command = PLDM_GET_PLDM_TYPES;
240 
241 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
242 	if (rc != PLDM_SUCCESS) {
243 		return rc;
244 	}
245 
246 	struct pldm_get_types_resp *response =
247 		(struct pldm_get_types_resp *)msg->payload;
248 	response->completion_code = completion_code;
249 	if (response->completion_code == PLDM_SUCCESS) {
250 		if (types == NULL) {
251 			return PLDM_ERROR_INVALID_DATA;
252 		}
253 		memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8);
254 	}
255 
256 	return PLDM_SUCCESS;
257 }
258 
259 LIBPLDM_ABI_STABLE
decode_get_commands_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * type,ver32_t * version)260 int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
261 			    uint8_t *type, ver32_t *version)
262 {
263 	if (msg == NULL || type == NULL || version == NULL) {
264 		return PLDM_ERROR_INVALID_DATA;
265 	}
266 
267 	if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) {
268 		return PLDM_ERROR_INVALID_LENGTH;
269 	}
270 
271 	struct pldm_get_commands_req *request =
272 		(struct pldm_get_commands_req *)msg->payload;
273 	*type = request->type;
274 	*version = request->version;
275 	return PLDM_SUCCESS;
276 }
277 
278 LIBPLDM_ABI_STABLE
encode_get_commands_resp(uint8_t instance_id,uint8_t completion_code,const bitfield8_t * commands,struct pldm_msg * msg)279 int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
280 			     const bitfield8_t *commands, struct pldm_msg *msg)
281 {
282 	if (msg == NULL) {
283 		return PLDM_ERROR_INVALID_DATA;
284 	}
285 
286 	struct pldm_header_info header = { 0 };
287 	header.instance = instance_id;
288 	header.msg_type = PLDM_RESPONSE;
289 	header.command = PLDM_GET_PLDM_COMMANDS;
290 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
291 	if (rc != PLDM_SUCCESS) {
292 		return rc;
293 	}
294 
295 	struct pldm_get_commands_resp *response =
296 		(struct pldm_get_commands_resp *)msg->payload;
297 	response->completion_code = completion_code;
298 	if (response->completion_code == PLDM_SUCCESS) {
299 		if (commands == NULL) {
300 			return PLDM_ERROR_INVALID_DATA;
301 		}
302 		memcpy(response->commands, &(commands->byte),
303 		       PLDM_MAX_CMDS_PER_TYPE / 8);
304 	}
305 
306 	return PLDM_SUCCESS;
307 }
308 
309 LIBPLDM_ABI_STABLE
decode_get_types_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,bitfield8_t * types)310 int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
311 			  uint8_t *completion_code, bitfield8_t *types)
312 {
313 	if (msg == NULL || types == NULL || completion_code == NULL) {
314 		return PLDM_ERROR_INVALID_DATA;
315 	}
316 
317 	*completion_code = msg->payload[0];
318 	if (PLDM_SUCCESS != *completion_code) {
319 		return PLDM_SUCCESS;
320 	}
321 
322 	if (payload_length != PLDM_GET_TYPES_RESP_BYTES) {
323 		return PLDM_ERROR_INVALID_LENGTH;
324 	}
325 
326 	struct pldm_get_types_resp *response =
327 		(struct pldm_get_types_resp *)msg->payload;
328 
329 	memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8);
330 
331 	return PLDM_SUCCESS;
332 }
333 
334 LIBPLDM_ABI_STABLE
decode_get_commands_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,bitfield8_t * commands)335 int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
336 			     uint8_t *completion_code, bitfield8_t *commands)
337 {
338 	if (msg == NULL || commands == NULL || completion_code == NULL) {
339 		return PLDM_ERROR_INVALID_DATA;
340 	}
341 
342 	*completion_code = msg->payload[0];
343 	if (PLDM_SUCCESS != *completion_code) {
344 		return PLDM_SUCCESS;
345 	}
346 
347 	if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) {
348 		return PLDM_ERROR_INVALID_LENGTH;
349 	}
350 
351 	struct pldm_get_commands_resp *response =
352 		(struct pldm_get_commands_resp *)msg->payload;
353 
354 	memcpy(&(commands->byte), response->commands,
355 	       PLDM_MAX_CMDS_PER_TYPE / 8);
356 
357 	return PLDM_SUCCESS;
358 }
359 
360 LIBPLDM_ABI_STABLE
encode_get_version_req(uint8_t instance_id,uint32_t transfer_handle,uint8_t transfer_opflag,uint8_t type,struct pldm_msg * msg)361 int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
362 			   uint8_t transfer_opflag, uint8_t type,
363 			   struct pldm_msg *msg)
364 {
365 	if (NULL == msg) {
366 		return PLDM_ERROR_INVALID_DATA;
367 	}
368 
369 	struct pldm_header_info header = { 0 };
370 	header.msg_type = PLDM_REQUEST;
371 	header.instance = instance_id;
372 	header.pldm_type = PLDM_BASE;
373 	header.command = PLDM_GET_PLDM_VERSION;
374 
375 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
376 	if (rc != PLDM_SUCCESS) {
377 		return rc;
378 	}
379 
380 	struct pldm_get_version_req *request =
381 		(struct pldm_get_version_req *)msg->payload;
382 	transfer_handle = htole32(transfer_handle);
383 	request->transfer_handle = transfer_handle;
384 	request->transfer_opflag = transfer_opflag;
385 	request->type = type;
386 
387 	return PLDM_SUCCESS;
388 }
389 
390 LIBPLDM_ABI_DEPRECATED_UNSAFE
encode_get_version_resp(uint8_t instance_id,uint8_t completion_code,uint32_t next_transfer_handle,uint8_t transfer_flag,const ver32_t * version_data,size_t version_size,struct pldm_msg * msg)391 int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code,
392 			    uint32_t next_transfer_handle,
393 			    uint8_t transfer_flag, const ver32_t *version_data,
394 			    size_t version_size, struct pldm_msg *msg)
395 {
396 	if (NULL == msg || NULL == version_data) {
397 		return PLDM_ERROR_INVALID_DATA;
398 	}
399 
400 	struct pldm_header_info header = { 0 };
401 	header.msg_type = PLDM_RESPONSE;
402 	header.instance = instance_id;
403 	header.pldm_type = PLDM_BASE;
404 	header.command = PLDM_GET_PLDM_VERSION;
405 
406 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
407 	if (rc != PLDM_SUCCESS) {
408 		return rc;
409 	}
410 
411 	struct pldm_get_version_resp *response =
412 		(struct pldm_get_version_resp *)msg->payload;
413 	response->completion_code = completion_code;
414 	if (response->completion_code == PLDM_SUCCESS) {
415 		response->next_transfer_handle = htole32(next_transfer_handle);
416 		response->transfer_flag = transfer_flag;
417 		memcpy(response->version_data, (uint8_t *)version_data,
418 		       version_size);
419 	}
420 	return PLDM_SUCCESS;
421 }
422 
423 LIBPLDM_ABI_STABLE
decode_get_version_req(const struct pldm_msg * msg,size_t payload_length,uint32_t * transfer_handle,uint8_t * transfer_opflag,uint8_t * type)424 int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length,
425 			   uint32_t *transfer_handle, uint8_t *transfer_opflag,
426 			   uint8_t *type)
427 {
428 	if (payload_length != PLDM_GET_VERSION_REQ_BYTES) {
429 		return PLDM_ERROR_INVALID_LENGTH;
430 	}
431 
432 	struct pldm_get_version_req *request =
433 		(struct pldm_get_version_req *)msg->payload;
434 	*transfer_handle = le32toh(request->transfer_handle);
435 	*transfer_opflag = request->transfer_opflag;
436 	*type = request->type;
437 	return PLDM_SUCCESS;
438 }
439 
440 LIBPLDM_ABI_STABLE
decode_get_version_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,uint32_t * next_transfer_handle,uint8_t * transfer_flag,ver32_t * version)441 int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length,
442 			    uint8_t *completion_code,
443 			    uint32_t *next_transfer_handle,
444 			    uint8_t *transfer_flag, ver32_t *version)
445 {
446 	if (msg == NULL || next_transfer_handle == NULL ||
447 	    transfer_flag == NULL || completion_code == NULL) {
448 		return PLDM_ERROR_INVALID_DATA;
449 	}
450 
451 	*completion_code = msg->payload[0];
452 	if (PLDM_SUCCESS != *completion_code) {
453 		return PLDM_SUCCESS;
454 	}
455 
456 	if (payload_length < PLDM_GET_VERSION_RESP_BYTES) {
457 		return PLDM_ERROR_INVALID_LENGTH;
458 	}
459 
460 	struct pldm_get_version_resp *response =
461 		(struct pldm_get_version_resp *)msg->payload;
462 
463 	*next_transfer_handle = le32toh(response->next_transfer_handle);
464 	*transfer_flag = response->transfer_flag;
465 	memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t));
466 
467 	return PLDM_SUCCESS;
468 }
469 
470 LIBPLDM_ABI_STABLE
encode_get_tid_req(uint8_t instance_id,struct pldm_msg * msg)471 int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg)
472 {
473 	if (msg == NULL) {
474 		return PLDM_ERROR_INVALID_DATA;
475 	}
476 
477 	struct pldm_header_info header = { 0 };
478 	header.instance = instance_id;
479 	header.msg_type = PLDM_REQUEST;
480 	header.command = PLDM_GET_TID;
481 
482 	return pack_pldm_header(&header, &(msg->hdr));
483 }
484 
485 LIBPLDM_ABI_STABLE
encode_get_tid_resp(uint8_t instance_id,uint8_t completion_code,uint8_t tid,struct pldm_msg * msg)486 int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
487 			uint8_t tid, struct pldm_msg *msg)
488 {
489 	if (msg == NULL) {
490 		return PLDM_ERROR_INVALID_DATA;
491 	}
492 
493 	struct pldm_header_info header = { 0 };
494 	header.instance = instance_id;
495 	header.msg_type = PLDM_RESPONSE;
496 	header.command = PLDM_GET_TID;
497 
498 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
499 	if (rc != PLDM_SUCCESS) {
500 		return rc;
501 	}
502 
503 	struct pldm_get_tid_resp *response =
504 		(struct pldm_get_tid_resp *)msg->payload;
505 	response->completion_code = completion_code;
506 	response->tid = tid;
507 
508 	return PLDM_SUCCESS;
509 }
510 
511 LIBPLDM_ABI_STABLE
decode_get_tid_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,uint8_t * tid)512 int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
513 			uint8_t *completion_code, uint8_t *tid)
514 {
515 	if (msg == NULL || tid == NULL || completion_code == NULL) {
516 		return PLDM_ERROR_INVALID_DATA;
517 	}
518 
519 	*completion_code = msg->payload[0];
520 	if (PLDM_SUCCESS != *completion_code) {
521 		return PLDM_SUCCESS;
522 	}
523 
524 	if (payload_length != PLDM_GET_TID_RESP_BYTES) {
525 		return PLDM_ERROR_INVALID_LENGTH;
526 	}
527 
528 	struct pldm_get_tid_resp *response =
529 		(struct pldm_get_tid_resp *)msg->payload;
530 
531 	*tid = response->tid;
532 
533 	return PLDM_SUCCESS;
534 }
535 
536 LIBPLDM_ABI_STABLE
encode_set_tid_req(uint8_t instance_id,uint8_t tid,struct pldm_msg * msg)537 int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg)
538 {
539 	if (msg == NULL) {
540 		return PLDM_ERROR_INVALID_DATA;
541 	}
542 
543 	if (tid == 0x0 || tid == 0xff) {
544 		return PLDM_ERROR_INVALID_DATA;
545 	}
546 
547 	struct pldm_header_info header = { 0 };
548 	header.instance = instance_id;
549 	header.msg_type = PLDM_REQUEST;
550 	header.command = PLDM_SET_TID;
551 
552 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
553 	if (rc != PLDM_SUCCESS) {
554 		return rc;
555 	}
556 
557 	struct pldm_set_tid_req *request =
558 		(struct pldm_set_tid_req *)msg->payload;
559 	request->tid = tid;
560 
561 	return PLDM_SUCCESS;
562 }
563 
564 LIBPLDM_ABI_TESTING
decode_set_tid_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * tid)565 int decode_set_tid_req(const struct pldm_msg *msg, size_t payload_length,
566 		       uint8_t *tid)
567 {
568 	PLDM_MSGBUF_RO_DEFINE_P(buf);
569 	int rc;
570 
571 	if (!msg || !tid) {
572 		return -EINVAL;
573 	}
574 
575 	rc = pldm_msgbuf_init_errno(buf, PLDM_SET_TID_REQ_BYTES, msg->payload,
576 				    payload_length);
577 	if (rc) {
578 		return rc;
579 	}
580 
581 	pldm_msgbuf_extract_p(buf, tid);
582 
583 	return pldm_msgbuf_complete_consumed(buf);
584 }
585 
586 LIBPLDM_ABI_STABLE
decode_multipart_receive_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * pldm_type,uint8_t * transfer_opflag,uint32_t * transfer_ctx,uint32_t * transfer_handle,uint32_t * section_offset,uint32_t * section_length)587 int decode_multipart_receive_req(const struct pldm_msg *msg,
588 				 size_t payload_length, uint8_t *pldm_type,
589 				 uint8_t *transfer_opflag,
590 				 uint32_t *transfer_ctx,
591 				 uint32_t *transfer_handle,
592 				 uint32_t *section_offset,
593 				 uint32_t *section_length)
594 {
595 	PLDM_MSGBUF_RO_DEFINE_P(buf);
596 	int rc;
597 
598 	if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
599 	    transfer_ctx == NULL || transfer_handle == NULL ||
600 	    section_offset == NULL || section_length == NULL) {
601 		return PLDM_ERROR_INVALID_DATA;
602 	}
603 
604 	rc = pldm_msgbuf_init_errno(buf, PLDM_MULTIPART_RECEIVE_REQ_BYTES,
605 				    msg->payload, payload_length);
606 	if (rc) {
607 		return pldm_xlate_errno(rc);
608 	}
609 
610 	pldm_msgbuf_extract_p(buf, pldm_type);
611 	pldm_msgbuf_extract_p(buf, transfer_opflag);
612 	pldm_msgbuf_extract_p(buf, transfer_ctx);
613 	pldm_msgbuf_extract_p(buf, transfer_handle);
614 	pldm_msgbuf_extract_p(buf, section_offset);
615 	pldm_msgbuf_extract_p(buf, section_length);
616 
617 	rc = pldm_msgbuf_complete_consumed(buf);
618 	if (rc) {
619 		return pldm_xlate_errno(rc);
620 	}
621 
622 	if (*pldm_type != PLDM_BASE && *pldm_type != PLDM_FILE) {
623 		return PLDM_ERROR_INVALID_PLDM_TYPE;
624 	}
625 
626 	// Any enum value above PLDM_XFER_CURRENT_PART is invalid.
627 	if (*transfer_opflag > PLDM_XFER_CURRENT_PART) {
628 		return PLDM_ERROR_UNEXPECTED_TRANSFER_FLAG_OPERATION;
629 	}
630 
631 	// By DSP0240 v1.2.0, section 9.6.5, Table 17, transfer handle can be 0 only
632 	// if the transfer flag is one of XFER_FIRST_PART, XFER_COMPLETE or
633 	// XFER_ABORT. In addition, it must be allowed in PLDM_XFER_CURRENT_PART as
634 	// this may be used to retry the first part, in which case the transfer handle
635 	// must again be 0. Therefore, the only operation for which it cannot be 0 is
636 	// PLDM_XFER_NEXT_PART.
637 	if ((*transfer_handle == 0) &&
638 	    (*transfer_opflag == PLDM_XFER_NEXT_PART)) {
639 		return PLDM_ERROR_INVALID_DATA;
640 	}
641 
642 	return PLDM_SUCCESS;
643 }
644 
645 LIBPLDM_ABI_STABLE
encode_pldm_base_multipart_receive_req(uint8_t instance_id,const struct pldm_base_multipart_receive_req * req,struct pldm_msg * msg,size_t * payload_length)646 int encode_pldm_base_multipart_receive_req(
647 	uint8_t instance_id, const struct pldm_base_multipart_receive_req *req,
648 	struct pldm_msg *msg, size_t *payload_length)
649 {
650 	PLDM_MSGBUF_RW_DEFINE_P(buf);
651 	int rc;
652 
653 	if (req == NULL || msg == NULL || payload_length == NULL) {
654 		return -EINVAL;
655 	}
656 
657 	struct pldm_header_info header = { 0 };
658 	header.instance = instance_id;
659 	header.msg_type = PLDM_REQUEST;
660 	header.pldm_type = PLDM_BASE;
661 	header.command = PLDM_MULTIPART_RECEIVE;
662 
663 	rc = pack_pldm_header_errno(&header, &msg->hdr);
664 	if (rc) {
665 		return rc;
666 	}
667 
668 	rc = pldm_msgbuf_init_errno(buf, PLDM_MULTIPART_RECEIVE_REQ_BYTES,
669 				    msg->payload, *payload_length);
670 	if (rc) {
671 		return rc;
672 	}
673 
674 	pldm_msgbuf_insert(buf, req->pldm_type);
675 	pldm_msgbuf_insert(buf, req->transfer_opflag);
676 	pldm_msgbuf_insert(buf, req->transfer_ctx);
677 	pldm_msgbuf_insert(buf, req->transfer_handle);
678 	pldm_msgbuf_insert(buf, req->section_offset);
679 	pldm_msgbuf_insert(buf, req->section_length);
680 
681 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
682 }
683 
684 LIBPLDM_ABI_STABLE
decode_pldm_base_multipart_receive_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_base_multipart_receive_resp * resp,uint32_t * data_integrity_checksum)685 int decode_pldm_base_multipart_receive_resp(
686 	const struct pldm_msg *msg, size_t payload_length,
687 	struct pldm_base_multipart_receive_resp *resp,
688 	uint32_t *data_integrity_checksum)
689 {
690 	PLDM_MSGBUF_RO_DEFINE_P(buf);
691 	int rc;
692 
693 	if (msg == NULL || resp == NULL || data_integrity_checksum == NULL) {
694 		return -EINVAL;
695 	}
696 
697 	rc = pldm_msg_has_error(msg, payload_length);
698 
699 	if (rc) {
700 		resp->completion_code = rc;
701 		return 0;
702 	}
703 
704 	rc = pldm_msgbuf_init_errno(buf,
705 				    PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
706 				    msg->payload, payload_length);
707 	if (rc) {
708 		return rc;
709 	}
710 
711 	pldm_msgbuf_extract(buf, resp->completion_code);
712 	rc = pldm_msgbuf_extract(buf, resp->transfer_flag);
713 	if (rc) {
714 		return pldm_msgbuf_discard(buf, rc);
715 	}
716 	pldm_msgbuf_extract(buf, resp->next_transfer_handle);
717 
718 	rc = pldm_msgbuf_extract_uint32_to_size(buf, resp->data.length);
719 	if (rc) {
720 		return pldm_msgbuf_discard(buf, rc);
721 	}
722 
723 	if (resp->data.length > 0) {
724 		resp->data.ptr = NULL;
725 		pldm_msgbuf_span_required(buf, resp->data.length,
726 					  (const void **)&resp->data.ptr);
727 	}
728 
729 	if (resp->transfer_flag !=
730 	    PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_ACK_COMPLETION) {
731 		pldm_msgbuf_extract_p(buf, data_integrity_checksum);
732 	}
733 
734 	return pldm_msgbuf_complete_consumed(buf);
735 }
736 
737 LIBPLDM_ABI_TESTING
encode_base_multipart_receive_resp(uint8_t instance_id,const struct pldm_base_multipart_receive_resp * resp,uint32_t checksum,struct pldm_msg * msg,size_t * payload_length)738 int encode_base_multipart_receive_resp(
739 	uint8_t instance_id,
740 	const struct pldm_base_multipart_receive_resp *resp, uint32_t checksum,
741 	struct pldm_msg *msg, size_t *payload_length)
742 {
743 	PLDM_MSGBUF_RW_DEFINE_P(buf);
744 	int rc;
745 
746 	if (!msg || !resp || !payload_length) {
747 		return -EINVAL;
748 	}
749 
750 	if ((resp->data.length > 0) && !resp->data.ptr) {
751 		return -EINVAL;
752 	}
753 
754 	struct pldm_header_info header = { 0 };
755 	header.instance = instance_id;
756 	header.msg_type = PLDM_RESPONSE;
757 	header.pldm_type = PLDM_BASE;
758 	header.command = PLDM_MULTIPART_RECEIVE;
759 
760 	rc = pack_pldm_header_errno(&header, &msg->hdr);
761 	if (rc) {
762 		return rc;
763 	}
764 
765 	rc = pldm_msgbuf_init_errno(buf,
766 				    PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
767 				    msg->payload, *payload_length);
768 	if (rc) {
769 		return rc;
770 	}
771 
772 	pldm_msgbuf_insert(buf, resp->completion_code);
773 	if (resp->completion_code != PLDM_SUCCESS) {
774 		// Return without encoding the rest of the field
775 		return pldm_msgbuf_complete_used(buf, *payload_length,
776 						 payload_length);
777 	}
778 
779 	pldm_msgbuf_insert(buf, resp->transfer_flag);
780 	pldm_msgbuf_insert(buf, resp->next_transfer_handle);
781 
782 	pldm_msgbuf_insert_uint32(buf, resp->data.length);
783 	if (resp->data.length == 0) {
784 		// Return without encoding data payload
785 		return pldm_msgbuf_complete_used(buf, *payload_length,
786 						 payload_length);
787 	}
788 
789 	rc = pldm_msgbuf_insert_array(buf, resp->data.length, resp->data.ptr,
790 				      resp->data.length);
791 	if (rc) {
792 		return pldm_msgbuf_discard(buf, rc);
793 	}
794 
795 	// Checksum is present for all data parts except when response transfer flag is
796 	// ACKNOWLEDGE_COMPLETION
797 	if (resp->transfer_flag !=
798 	    PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_ACK_COMPLETION) {
799 		pldm_msgbuf_insert(buf, checksum);
800 	}
801 
802 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
803 }
804 
805 LIBPLDM_ABI_STABLE
encode_cc_only_resp(uint8_t instance_id,uint8_t type,uint8_t command,uint8_t cc,struct pldm_msg * msg)806 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
807 			uint8_t cc, struct pldm_msg *msg)
808 {
809 	if (msg == NULL) {
810 		return PLDM_ERROR_INVALID_DATA;
811 	}
812 
813 	struct pldm_header_info header = { 0 };
814 	header.instance = instance_id;
815 	header.msg_type = PLDM_RESPONSE;
816 	header.pldm_type = type;
817 	header.command = command;
818 
819 	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
820 	if (rc != PLDM_SUCCESS) {
821 		return rc;
822 	}
823 
824 	msg->payload[0] = cc;
825 
826 	return PLDM_SUCCESS;
827 }
828 
encode_pldm_header_only_errno(uint8_t msg_type,uint8_t instance_id,uint8_t pldm_type,uint8_t command,struct pldm_msg * msg)829 int encode_pldm_header_only_errno(uint8_t msg_type, uint8_t instance_id,
830 				  uint8_t pldm_type, uint8_t command,
831 				  struct pldm_msg *msg)
832 {
833 	if (msg == NULL) {
834 		return -EINVAL;
835 	}
836 
837 	struct pldm_header_info header = { 0 };
838 	header.msg_type = msg_type;
839 	header.instance = instance_id;
840 	header.pldm_type = pldm_type;
841 	header.command = command;
842 	return pack_pldm_header_errno(&header, &(msg->hdr));
843 }
844 
845 LIBPLDM_ABI_STABLE
encode_pldm_header_only(uint8_t msg_type,uint8_t instance_id,uint8_t pldm_type,uint8_t command,struct pldm_msg * msg)846 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
847 			    uint8_t pldm_type, uint8_t command,
848 			    struct pldm_msg *msg)
849 {
850 	int rc = encode_pldm_header_only_errno(msg_type, instance_id, pldm_type,
851 					       command, msg);
852 	if (rc) {
853 		return pldm_xlate_errno(rc);
854 	}
855 	return PLDM_SUCCESS;
856 }
857 
858 LIBPLDM_ABI_STABLE
encode_pldm_base_negotiate_transfer_params_req(uint8_t instance_id,const struct pldm_base_negotiate_transfer_params_req * req,struct pldm_msg * msg,size_t * payload_length)859 int encode_pldm_base_negotiate_transfer_params_req(
860 	uint8_t instance_id,
861 	const struct pldm_base_negotiate_transfer_params_req *req,
862 	struct pldm_msg *msg, size_t *payload_length)
863 {
864 	PLDM_MSGBUF_RW_DEFINE_P(buf);
865 	int rc;
866 
867 	if (req == NULL || msg == NULL || payload_length == NULL) {
868 		return -EINVAL;
869 	}
870 
871 	struct pldm_header_info header = { 0 };
872 	header.instance = instance_id;
873 	header.msg_type = PLDM_REQUEST;
874 	header.pldm_type = PLDM_BASE;
875 	header.command = PLDM_NEGOTIATE_TRANSFER_PARAMETERS;
876 
877 	rc = pack_pldm_header_errno(&header, &msg->hdr);
878 	if (rc) {
879 		return rc;
880 	}
881 
882 	rc = pldm_msgbuf_init_errno(
883 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES,
884 		msg->payload, *payload_length);
885 	if (rc) {
886 		return rc;
887 	}
888 
889 	pldm_msgbuf_insert(buf, req->requester_part_size);
890 	rc = pldm_msgbuf_insert_array(
891 		buf, sizeof(req->requester_protocol_support),
892 		(uint8_t *)req->requester_protocol_support,
893 		sizeof(req->requester_protocol_support));
894 	if (rc) {
895 		return pldm_msgbuf_discard(buf, rc);
896 	}
897 
898 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
899 }
900 
901 #define PLDM_BASE_MIN_PART_SIZE 256
902 
903 LIBPLDM_ABI_TESTING
encode_pldm_base_negotiate_transfer_params_resp(uint8_t instance_id,const struct pldm_base_negotiate_transfer_params_resp * resp,struct pldm_msg * msg,size_t * payload_length)904 int encode_pldm_base_negotiate_transfer_params_resp(
905 	uint8_t instance_id,
906 	const struct pldm_base_negotiate_transfer_params_resp *resp,
907 	struct pldm_msg *msg, size_t *payload_length)
908 {
909 	PLDM_MSGBUF_RW_DEFINE_P(buf);
910 	int rc;
911 
912 	if (resp == NULL || msg == NULL) {
913 		return -EINVAL;
914 	}
915 
916 	if (resp->responder_part_size < PLDM_BASE_MIN_PART_SIZE) {
917 		return -EINVAL;
918 	}
919 
920 	struct pldm_header_info header = { 0 };
921 	header.instance = instance_id;
922 	header.msg_type = PLDM_RESPONSE;
923 	header.pldm_type = PLDM_BASE;
924 	header.command = PLDM_NEGOTIATE_TRANSFER_PARAMETERS;
925 
926 	rc = pack_pldm_header_errno(&header, &msg->hdr);
927 	if (rc) {
928 		return rc;
929 	}
930 
931 	rc = pldm_msgbuf_init_errno(
932 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES,
933 		msg->payload, *payload_length);
934 	if (rc) {
935 		return rc;
936 	}
937 
938 	pldm_msgbuf_insert(buf, resp->completion_code);
939 	pldm_msgbuf_insert(buf, resp->responder_part_size);
940 	rc = pldm_msgbuf_insert_array(
941 		buf, sizeof(resp->responder_protocol_support),
942 		(uint8_t *)resp->responder_protocol_support,
943 		sizeof(resp->responder_protocol_support));
944 	if (rc) {
945 		return pldm_msgbuf_discard(buf, rc);
946 	}
947 
948 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
949 }
950 
951 LIBPLDM_ABI_TESTING
decode_pldm_base_negotiate_transfer_params_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_base_negotiate_transfer_params_req * req)952 int decode_pldm_base_negotiate_transfer_params_req(
953 	const struct pldm_msg *msg, size_t payload_length,
954 	struct pldm_base_negotiate_transfer_params_req *req)
955 {
956 	PLDM_MSGBUF_RO_DEFINE_P(buf);
957 	int rc;
958 
959 	if (msg == NULL || req == NULL) {
960 		return -EINVAL;
961 	}
962 
963 	rc = pldm_msgbuf_init_errno(
964 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES,
965 		msg->payload, payload_length);
966 	if (rc) {
967 		return rc;
968 	}
969 
970 	pldm_msgbuf_extract(buf, req->requester_part_size);
971 
972 	rc = pldm_msgbuf_extract_array(
973 		buf, sizeof(req->requester_protocol_support),
974 		(uint8_t *)req->requester_protocol_support,
975 		sizeof(req->requester_protocol_support));
976 	if (rc) {
977 		return pldm_msgbuf_discard(buf, rc);
978 	}
979 
980 	return pldm_msgbuf_complete_consumed(buf);
981 }
982 
983 LIBPLDM_ABI_STABLE
decode_pldm_base_negotiate_transfer_params_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_base_negotiate_transfer_params_resp * resp)984 int decode_pldm_base_negotiate_transfer_params_resp(
985 	const struct pldm_msg *msg, size_t payload_length,
986 	struct pldm_base_negotiate_transfer_params_resp *resp)
987 {
988 	PLDM_MSGBUF_RO_DEFINE_P(buf);
989 	int rc;
990 
991 	if (msg == NULL || resp == NULL) {
992 		return -EINVAL;
993 	}
994 
995 	rc = pldm_msg_has_error(msg, payload_length);
996 
997 	if (rc) {
998 		resp->completion_code = rc;
999 		return 0;
1000 	}
1001 
1002 	rc = pldm_msgbuf_init_errno(
1003 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES,
1004 		msg->payload, payload_length);
1005 	if (rc) {
1006 		return rc;
1007 	}
1008 
1009 	pldm_msgbuf_extract(buf, resp->completion_code);
1010 	pldm_msgbuf_extract(buf, resp->responder_part_size);
1011 	rc = pldm_msgbuf_extract_array(
1012 		buf, sizeof(resp->responder_protocol_support),
1013 		(uint8_t *)resp->responder_protocol_support,
1014 		sizeof(resp->responder_protocol_support));
1015 	if (rc) {
1016 		return pldm_msgbuf_discard(buf, rc);
1017 	}
1018 
1019 	return pldm_msgbuf_complete_consumed(buf);
1020 }
1021