xref: /openbmc/libpldm/src/dsp/base.c (revision 309bbe8f157023f3e6e1dbbb3548f40ddcaf4cbd)
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 <stdint.h>
13 #include <string.h>
14 
pack_pldm_header_errno(const struct pldm_header_info * hdr,struct pldm_msg_hdr * msg)15 int pack_pldm_header_errno(const struct pldm_header_info *hdr,
16 			   struct pldm_msg_hdr *msg)
17 {
18 	if (msg == NULL || hdr == NULL) {
19 		return -EINVAL;
20 	}
21 
22 	if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST &&
23 	    hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) {
24 		return -EINVAL;
25 	}
26 
27 	if (hdr->instance > PLDM_INSTANCE_MAX) {
28 		return -EINVAL;
29 	}
30 
31 	if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) {
32 		return -ENOMSG;
33 	}
34 
35 	uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0;
36 
37 	if (hdr->msg_type == PLDM_RESPONSE) {
38 		msg->request = PLDM_RESPONSE;
39 	} else if (hdr->msg_type == PLDM_REQUEST ||
40 		   hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) {
41 		msg->request = PLDM_REQUEST;
42 	}
43 	msg->datagram = datagram;
44 	msg->reserved = 0;
45 	msg->instance_id = hdr->instance;
46 	msg->header_ver = PLDM_CURRENT_VERSION;
47 	msg->type = hdr->pldm_type;
48 	msg->command = hdr->command;
49 
50 	return 0;
51 }
52 
unpack_pldm_header_errno(const struct pldm_msg_hdr * msg,struct pldm_header_info * hdr)53 int unpack_pldm_header_errno(const struct pldm_msg_hdr *msg,
54 			     struct pldm_header_info *hdr)
55 {
56 	if (msg == NULL) {
57 		return -EINVAL;
58 	}
59 
60 	if (msg->request == PLDM_RESPONSE) {
61 		hdr->msg_type = PLDM_RESPONSE;
62 	} else {
63 		hdr->msg_type = msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY :
64 						PLDM_REQUEST;
65 	}
66 
67 	hdr->instance = msg->instance_id;
68 	hdr->pldm_type = msg->type;
69 	hdr->command = msg->command;
70 
71 	return 0;
72 }
73 
74 LIBPLDM_ABI_STABLE
pack_pldm_header(const struct pldm_header_info * hdr,struct pldm_msg_hdr * msg)75 uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
76 			 struct pldm_msg_hdr *msg)
77 {
78 	enum pldm_completion_codes cc;
79 	int rc;
80 
81 	rc = pack_pldm_header_errno(hdr, msg);
82 	if (!rc) {
83 		return PLDM_SUCCESS;
84 	}
85 
86 	cc = pldm_xlate_errno(rc);
87 	assert(cc < UINT8_MAX);
88 	if (cc > UINT8_MAX) {
89 		static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error");
90 		return PLDM_ERROR;
91 	}
92 
93 	return cc;
94 }
95 
96 LIBPLDM_ABI_STABLE
unpack_pldm_header(const struct pldm_msg_hdr * msg,struct pldm_header_info * hdr)97 uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
98 			   struct pldm_header_info *hdr)
99 {
100 	enum pldm_completion_codes cc;
101 	int rc;
102 
103 	rc = unpack_pldm_header_errno(msg, hdr);
104 	if (!rc) {
105 		return PLDM_SUCCESS;
106 	}
107 
108 	cc = pldm_xlate_errno(rc);
109 	assert(cc < UINT8_MAX);
110 	if (cc > UINT8_MAX) {
111 		static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error");
112 		return PLDM_ERROR;
113 	}
114 
115 	return cc;
116 }
117 
118 LIBPLDM_ABI_STABLE
pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr * req,const struct pldm_msg_hdr * resp)119 bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req,
120 				     const struct pldm_msg_hdr *resp)
121 {
122 	return req->instance_id == resp->instance_id && req->request &&
123 	       !resp->request && req->type == resp->type &&
124 	       req->command == resp->command;
125 }
126 
127 LIBPLDM_ABI_STABLE
encode_get_types_req(uint8_t instance_id,struct pldm_msg * msg)128 int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
129 {
130 	if (msg == NULL) {
131 		return PLDM_ERROR_INVALID_DATA;
132 	}
133 
134 	struct pldm_header_info header = { 0 };
135 	header.instance = instance_id;
136 	header.msg_type = PLDM_REQUEST;
137 	header.command = PLDM_GET_PLDM_TYPES;
138 
139 	return pack_pldm_header(&header, &(msg->hdr));
140 }
141 
142 LIBPLDM_ABI_STABLE
encode_get_commands_req(uint8_t instance_id,uint8_t type,ver32_t version,struct pldm_msg * msg)143 int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
144 			    struct pldm_msg *msg)
145 {
146 	if (msg == NULL) {
147 		return PLDM_ERROR_INVALID_DATA;
148 	}
149 
150 	struct pldm_header_info header = { 0 };
151 	header.instance = instance_id;
152 	header.msg_type = PLDM_REQUEST;
153 	header.command = PLDM_GET_PLDM_COMMANDS;
154 
155 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
156 	if (rc != PLDM_SUCCESS) {
157 		return rc;
158 	}
159 
160 	struct pldm_get_commands_req *request =
161 		(struct pldm_get_commands_req *)msg->payload;
162 
163 	request->type = type;
164 	request->version = version;
165 
166 	return PLDM_SUCCESS;
167 }
168 
169 LIBPLDM_ABI_STABLE
encode_get_types_resp(uint8_t instance_id,uint8_t completion_code,const bitfield8_t * types,struct pldm_msg * msg)170 int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
171 			  const bitfield8_t *types, struct pldm_msg *msg)
172 {
173 	if (msg == NULL) {
174 		return PLDM_ERROR_INVALID_DATA;
175 	}
176 
177 	struct pldm_header_info header = { 0 };
178 	header.instance = instance_id;
179 	header.msg_type = PLDM_RESPONSE;
180 	header.command = PLDM_GET_PLDM_TYPES;
181 
182 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
183 	if (rc != PLDM_SUCCESS) {
184 		return rc;
185 	}
186 
187 	struct pldm_get_types_resp *response =
188 		(struct pldm_get_types_resp *)msg->payload;
189 	response->completion_code = completion_code;
190 	if (response->completion_code == PLDM_SUCCESS) {
191 		if (types == NULL) {
192 			return PLDM_ERROR_INVALID_DATA;
193 		}
194 		memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8);
195 	}
196 
197 	return PLDM_SUCCESS;
198 }
199 
200 LIBPLDM_ABI_STABLE
decode_get_commands_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * type,ver32_t * version)201 int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
202 			    uint8_t *type, ver32_t *version)
203 {
204 	if (msg == NULL || type == NULL || version == NULL) {
205 		return PLDM_ERROR_INVALID_DATA;
206 	}
207 
208 	if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) {
209 		return PLDM_ERROR_INVALID_LENGTH;
210 	}
211 
212 	struct pldm_get_commands_req *request =
213 		(struct pldm_get_commands_req *)msg->payload;
214 	*type = request->type;
215 	*version = request->version;
216 	return PLDM_SUCCESS;
217 }
218 
219 LIBPLDM_ABI_STABLE
encode_get_commands_resp(uint8_t instance_id,uint8_t completion_code,const bitfield8_t * commands,struct pldm_msg * msg)220 int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
221 			     const bitfield8_t *commands, struct pldm_msg *msg)
222 {
223 	if (msg == NULL) {
224 		return PLDM_ERROR_INVALID_DATA;
225 	}
226 
227 	struct pldm_header_info header = { 0 };
228 	header.instance = instance_id;
229 	header.msg_type = PLDM_RESPONSE;
230 	header.command = PLDM_GET_PLDM_COMMANDS;
231 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
232 	if (rc != PLDM_SUCCESS) {
233 		return rc;
234 	}
235 
236 	struct pldm_get_commands_resp *response =
237 		(struct pldm_get_commands_resp *)msg->payload;
238 	response->completion_code = completion_code;
239 	if (response->completion_code == PLDM_SUCCESS) {
240 		if (commands == NULL) {
241 			return PLDM_ERROR_INVALID_DATA;
242 		}
243 		memcpy(response->commands, &(commands->byte),
244 		       PLDM_MAX_CMDS_PER_TYPE / 8);
245 	}
246 
247 	return PLDM_SUCCESS;
248 }
249 
250 LIBPLDM_ABI_STABLE
decode_get_types_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,bitfield8_t * types)251 int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
252 			  uint8_t *completion_code, bitfield8_t *types)
253 {
254 	if (msg == NULL || types == NULL || completion_code == NULL) {
255 		return PLDM_ERROR_INVALID_DATA;
256 	}
257 
258 	*completion_code = msg->payload[0];
259 	if (PLDM_SUCCESS != *completion_code) {
260 		return PLDM_SUCCESS;
261 	}
262 
263 	if (payload_length != PLDM_GET_TYPES_RESP_BYTES) {
264 		return PLDM_ERROR_INVALID_LENGTH;
265 	}
266 
267 	struct pldm_get_types_resp *response =
268 		(struct pldm_get_types_resp *)msg->payload;
269 
270 	memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8);
271 
272 	return PLDM_SUCCESS;
273 }
274 
275 LIBPLDM_ABI_STABLE
decode_get_commands_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,bitfield8_t * commands)276 int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
277 			     uint8_t *completion_code, bitfield8_t *commands)
278 {
279 	if (msg == NULL || commands == NULL || completion_code == NULL) {
280 		return PLDM_ERROR_INVALID_DATA;
281 	}
282 
283 	*completion_code = msg->payload[0];
284 	if (PLDM_SUCCESS != *completion_code) {
285 		return PLDM_SUCCESS;
286 	}
287 
288 	if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) {
289 		return PLDM_ERROR_INVALID_LENGTH;
290 	}
291 
292 	struct pldm_get_commands_resp *response =
293 		(struct pldm_get_commands_resp *)msg->payload;
294 
295 	memcpy(&(commands->byte), response->commands,
296 	       PLDM_MAX_CMDS_PER_TYPE / 8);
297 
298 	return PLDM_SUCCESS;
299 }
300 
301 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)302 int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
303 			   uint8_t transfer_opflag, uint8_t type,
304 			   struct pldm_msg *msg)
305 {
306 	if (NULL == msg) {
307 		return PLDM_ERROR_INVALID_DATA;
308 	}
309 
310 	struct pldm_header_info header = { 0 };
311 	header.msg_type = PLDM_REQUEST;
312 	header.instance = instance_id;
313 	header.pldm_type = PLDM_BASE;
314 	header.command = PLDM_GET_PLDM_VERSION;
315 
316 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
317 	if (rc != PLDM_SUCCESS) {
318 		return rc;
319 	}
320 
321 	struct pldm_get_version_req *request =
322 		(struct pldm_get_version_req *)msg->payload;
323 	transfer_handle = htole32(transfer_handle);
324 	request->transfer_handle = transfer_handle;
325 	request->transfer_opflag = transfer_opflag;
326 	request->type = type;
327 
328 	return PLDM_SUCCESS;
329 }
330 
331 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)332 int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code,
333 			    uint32_t next_transfer_handle,
334 			    uint8_t transfer_flag, const ver32_t *version_data,
335 			    size_t version_size, struct pldm_msg *msg)
336 {
337 	if (NULL == msg || NULL == version_data) {
338 		return PLDM_ERROR_INVALID_DATA;
339 	}
340 
341 	struct pldm_header_info header = { 0 };
342 	header.msg_type = PLDM_RESPONSE;
343 	header.instance = instance_id;
344 	header.pldm_type = PLDM_BASE;
345 	header.command = PLDM_GET_PLDM_VERSION;
346 
347 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
348 	if (rc != PLDM_SUCCESS) {
349 		return rc;
350 	}
351 
352 	struct pldm_get_version_resp *response =
353 		(struct pldm_get_version_resp *)msg->payload;
354 	response->completion_code = completion_code;
355 	if (response->completion_code == PLDM_SUCCESS) {
356 		response->next_transfer_handle = htole32(next_transfer_handle);
357 		response->transfer_flag = transfer_flag;
358 		memcpy(response->version_data, (uint8_t *)version_data,
359 		       version_size);
360 	}
361 	return PLDM_SUCCESS;
362 }
363 
364 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)365 int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length,
366 			   uint32_t *transfer_handle, uint8_t *transfer_opflag,
367 			   uint8_t *type)
368 {
369 	if (payload_length != PLDM_GET_VERSION_REQ_BYTES) {
370 		return PLDM_ERROR_INVALID_LENGTH;
371 	}
372 
373 	struct pldm_get_version_req *request =
374 		(struct pldm_get_version_req *)msg->payload;
375 	*transfer_handle = le32toh(request->transfer_handle);
376 	*transfer_opflag = request->transfer_opflag;
377 	*type = request->type;
378 	return PLDM_SUCCESS;
379 }
380 
381 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)382 int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length,
383 			    uint8_t *completion_code,
384 			    uint32_t *next_transfer_handle,
385 			    uint8_t *transfer_flag, ver32_t *version)
386 {
387 	if (msg == NULL || next_transfer_handle == NULL ||
388 	    transfer_flag == NULL || completion_code == NULL) {
389 		return PLDM_ERROR_INVALID_DATA;
390 	}
391 
392 	*completion_code = msg->payload[0];
393 	if (PLDM_SUCCESS != *completion_code) {
394 		return PLDM_SUCCESS;
395 	}
396 
397 	if (payload_length < PLDM_GET_VERSION_RESP_BYTES) {
398 		return PLDM_ERROR_INVALID_LENGTH;
399 	}
400 
401 	struct pldm_get_version_resp *response =
402 		(struct pldm_get_version_resp *)msg->payload;
403 
404 	*next_transfer_handle = le32toh(response->next_transfer_handle);
405 	*transfer_flag = response->transfer_flag;
406 	memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t));
407 
408 	return PLDM_SUCCESS;
409 }
410 
411 LIBPLDM_ABI_STABLE
encode_get_tid_req(uint8_t instance_id,struct pldm_msg * msg)412 int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg)
413 {
414 	if (msg == NULL) {
415 		return PLDM_ERROR_INVALID_DATA;
416 	}
417 
418 	struct pldm_header_info header = { 0 };
419 	header.instance = instance_id;
420 	header.msg_type = PLDM_REQUEST;
421 	header.command = PLDM_GET_TID;
422 
423 	return pack_pldm_header(&header, &(msg->hdr));
424 }
425 
426 LIBPLDM_ABI_STABLE
encode_get_tid_resp(uint8_t instance_id,uint8_t completion_code,uint8_t tid,struct pldm_msg * msg)427 int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
428 			uint8_t tid, struct pldm_msg *msg)
429 {
430 	if (msg == NULL) {
431 		return PLDM_ERROR_INVALID_DATA;
432 	}
433 
434 	struct pldm_header_info header = { 0 };
435 	header.instance = instance_id;
436 	header.msg_type = PLDM_RESPONSE;
437 	header.command = PLDM_GET_TID;
438 
439 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
440 	if (rc != PLDM_SUCCESS) {
441 		return rc;
442 	}
443 
444 	struct pldm_get_tid_resp *response =
445 		(struct pldm_get_tid_resp *)msg->payload;
446 	response->completion_code = completion_code;
447 	response->tid = tid;
448 
449 	return PLDM_SUCCESS;
450 }
451 
452 LIBPLDM_ABI_STABLE
decode_get_tid_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code,uint8_t * tid)453 int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
454 			uint8_t *completion_code, uint8_t *tid)
455 {
456 	if (msg == NULL || tid == NULL || completion_code == NULL) {
457 		return PLDM_ERROR_INVALID_DATA;
458 	}
459 
460 	*completion_code = msg->payload[0];
461 	if (PLDM_SUCCESS != *completion_code) {
462 		return PLDM_SUCCESS;
463 	}
464 
465 	if (payload_length != PLDM_GET_TID_RESP_BYTES) {
466 		return PLDM_ERROR_INVALID_LENGTH;
467 	}
468 
469 	struct pldm_get_tid_resp *response =
470 		(struct pldm_get_tid_resp *)msg->payload;
471 
472 	*tid = response->tid;
473 
474 	return PLDM_SUCCESS;
475 }
476 
477 LIBPLDM_ABI_STABLE
encode_set_tid_req(uint8_t instance_id,uint8_t tid,struct pldm_msg * msg)478 int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg)
479 {
480 	if (msg == NULL) {
481 		return PLDM_ERROR_INVALID_DATA;
482 	}
483 
484 	if (tid == 0x0 || tid == 0xff) {
485 		return PLDM_ERROR_INVALID_DATA;
486 	}
487 
488 	struct pldm_header_info header = { 0 };
489 	header.instance = instance_id;
490 	header.msg_type = PLDM_REQUEST;
491 	header.command = PLDM_SET_TID;
492 
493 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
494 	if (rc != PLDM_SUCCESS) {
495 		return rc;
496 	}
497 
498 	struct pldm_set_tid_req *request =
499 		(struct pldm_set_tid_req *)msg->payload;
500 	request->tid = tid;
501 
502 	return PLDM_SUCCESS;
503 }
504 
505 LIBPLDM_ABI_TESTING
decode_set_tid_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * tid)506 int decode_set_tid_req(const struct pldm_msg *msg, size_t payload_length,
507 		       uint8_t *tid)
508 {
509 	PLDM_MSGBUF_DEFINE_P(buf);
510 	int rc;
511 
512 	if (!msg || !tid) {
513 		return -EINVAL;
514 	}
515 
516 	rc = pldm_msgbuf_init_errno(buf, PLDM_SET_TID_REQ_BYTES, msg->payload,
517 				    payload_length);
518 	if (rc) {
519 		return rc;
520 	}
521 
522 	pldm_msgbuf_extract_p(buf, tid);
523 
524 	return pldm_msgbuf_complete_consumed(buf);
525 }
526 
527 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)528 int decode_multipart_receive_req(const struct pldm_msg *msg,
529 				 size_t payload_length, uint8_t *pldm_type,
530 				 uint8_t *transfer_opflag,
531 				 uint32_t *transfer_ctx,
532 				 uint32_t *transfer_handle,
533 				 uint32_t *section_offset,
534 				 uint32_t *section_length)
535 {
536 	if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
537 	    transfer_ctx == NULL || transfer_handle == NULL ||
538 	    section_offset == NULL || section_length == NULL) {
539 		return PLDM_ERROR_INVALID_DATA;
540 	}
541 
542 	if (payload_length != PLDM_MULTIPART_RECEIVE_REQ_BYTES) {
543 		return PLDM_ERROR_INVALID_LENGTH;
544 	}
545 
546 	struct pldm_multipart_receive_req *request =
547 		(struct pldm_multipart_receive_req *)msg->payload;
548 
549 	if (request->pldm_type != PLDM_BASE) {
550 		return PLDM_ERROR_INVALID_PLDM_TYPE;
551 	}
552 
553 	// Any enum value above PLDM_XFER_CURRENT_PART is invalid.
554 	if (request->transfer_opflag > PLDM_XFER_CURRENT_PART) {
555 		return PLDM_ERROR_UNEXPECTED_TRANSFER_FLAG_OPERATION;
556 	}
557 
558 	// A section offset of 0 is only valid on FIRST_PART or COMPLETE Xfers.
559 	uint32_t sec_offset = le32toh(request->section_offset);
560 	if (sec_offset == 0 &&
561 	    (request->transfer_opflag != PLDM_XFER_FIRST_PART &&
562 	     request->transfer_opflag != PLDM_XFER_COMPLETE)) {
563 		return PLDM_ERROR_INVALID_DATA;
564 	}
565 
566 	uint32_t handle = le32toh(request->transfer_handle);
567 	if (handle == 0 && request->transfer_opflag != PLDM_XFER_COMPLETE) {
568 		return PLDM_ERROR_INVALID_DATA;
569 	}
570 
571 	*pldm_type = request->pldm_type;
572 	*transfer_opflag = request->transfer_opflag;
573 	*transfer_ctx = request->transfer_ctx;
574 	*transfer_handle = handle;
575 	*section_offset = sec_offset;
576 	*section_length = le32toh(request->section_length);
577 
578 	return PLDM_SUCCESS;
579 }
580 
581 LIBPLDM_ABI_TESTING
encode_base_multipart_receive_req(uint8_t instance_id,const struct pldm_multipart_receive_req * req,struct pldm_msg * msg,size_t payload_length)582 int encode_base_multipart_receive_req(
583 	uint8_t instance_id, const struct pldm_multipart_receive_req *req,
584 	struct pldm_msg *msg, size_t payload_length)
585 {
586 	PLDM_MSGBUF_DEFINE_P(buf);
587 	int rc;
588 
589 	if (req == NULL || msg == NULL) {
590 		return -EINVAL;
591 	}
592 
593 	struct pldm_header_info header = { 0 };
594 	header.instance = instance_id;
595 	header.msg_type = PLDM_REQUEST;
596 	header.pldm_type = PLDM_BASE;
597 	header.command = PLDM_MULTIPART_RECEIVE;
598 
599 	rc = pack_pldm_header_errno(&header, &msg->hdr);
600 	if (rc) {
601 		return rc;
602 	}
603 
604 	rc = pldm_msgbuf_init_errno(buf, PLDM_MULTIPART_RECEIVE_REQ_BYTES,
605 				    msg->payload, payload_length);
606 	if (rc) {
607 		return rc;
608 	}
609 
610 	pldm_msgbuf_insert(buf, req->pldm_type);
611 	pldm_msgbuf_insert(buf, req->transfer_opflag);
612 	pldm_msgbuf_insert(buf, req->transfer_ctx);
613 	pldm_msgbuf_insert(buf, req->transfer_handle);
614 	pldm_msgbuf_insert(buf, req->section_offset);
615 	pldm_msgbuf_insert(buf, req->section_length);
616 
617 	return pldm_msgbuf_complete(buf);
618 }
619 
620 LIBPLDM_ABI_TESTING
decode_base_multipart_receive_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_multipart_receive_resp * resp,uint32_t * data_integrity_checksum)621 int decode_base_multipart_receive_resp(const struct pldm_msg *msg,
622 				       size_t payload_length,
623 				       struct pldm_multipart_receive_resp *resp,
624 				       uint32_t *data_integrity_checksum)
625 {
626 	PLDM_MSGBUF_DEFINE_P(buf);
627 	int rc;
628 
629 	if (msg == NULL || resp == NULL || data_integrity_checksum == NULL) {
630 		return -EINVAL;
631 	}
632 
633 	rc = pldm_msg_has_error(msg, payload_length);
634 
635 	if (rc) {
636 		resp->completion_code = rc;
637 		return 0;
638 	}
639 
640 	rc = pldm_msgbuf_init_errno(buf,
641 				    PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
642 				    msg->payload, payload_length);
643 	if (rc) {
644 		return rc;
645 	}
646 
647 	pldm_msgbuf_extract(buf, resp->completion_code);
648 	rc = pldm_msgbuf_extract(buf, resp->transfer_flag);
649 	if (rc) {
650 		return pldm_msgbuf_discard(buf, rc);
651 	}
652 	pldm_msgbuf_extract(buf, resp->next_transfer_handle);
653 
654 	rc = pldm_msgbuf_extract_uint32_to_size(buf, resp->data.length);
655 	if (rc) {
656 		return pldm_msgbuf_discard(buf, rc);
657 	}
658 
659 	if (resp->data.length > 0) {
660 		resp->data.ptr = NULL;
661 		pldm_msgbuf_span_required(buf, resp->data.length,
662 					  (void **)&resp->data.ptr);
663 	}
664 
665 	if (resp->transfer_flag ==
666 		    PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_END ||
667 	    resp->transfer_flag ==
668 		    PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_START_AND_END) {
669 		pldm_msgbuf_extract_p(buf, data_integrity_checksum);
670 	}
671 
672 	return pldm_msgbuf_complete_consumed(buf);
673 }
674 
675 LIBPLDM_ABI_STABLE
encode_cc_only_resp(uint8_t instance_id,uint8_t type,uint8_t command,uint8_t cc,struct pldm_msg * msg)676 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
677 			uint8_t cc, struct pldm_msg *msg)
678 {
679 	if (msg == NULL) {
680 		return PLDM_ERROR_INVALID_DATA;
681 	}
682 
683 	struct pldm_header_info header = { 0 };
684 	header.instance = instance_id;
685 	header.msg_type = PLDM_RESPONSE;
686 	header.pldm_type = type;
687 	header.command = command;
688 
689 	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
690 	if (rc != PLDM_SUCCESS) {
691 		return rc;
692 	}
693 
694 	msg->payload[0] = cc;
695 
696 	return PLDM_SUCCESS;
697 }
698 
encode_pldm_header_only_errno(uint8_t msg_type,uint8_t instance_id,uint8_t pldm_type,uint8_t command,struct pldm_msg * msg)699 int encode_pldm_header_only_errno(uint8_t msg_type, uint8_t instance_id,
700 				  uint8_t pldm_type, uint8_t command,
701 				  struct pldm_msg *msg)
702 {
703 	if (msg == NULL) {
704 		return -EINVAL;
705 	}
706 
707 	struct pldm_header_info header = { 0 };
708 	header.msg_type = msg_type;
709 	header.instance = instance_id;
710 	header.pldm_type = pldm_type;
711 	header.command = command;
712 	return pack_pldm_header_errno(&header, &(msg->hdr));
713 }
714 
715 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)716 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
717 			    uint8_t pldm_type, uint8_t command,
718 			    struct pldm_msg *msg)
719 {
720 	int rc = encode_pldm_header_only_errno(msg_type, instance_id, pldm_type,
721 					       command, msg);
722 	if (rc) {
723 		return pldm_xlate_errno(rc);
724 	}
725 	return PLDM_SUCCESS;
726 }
727 
728 LIBPLDM_ABI_TESTING
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)729 int encode_pldm_base_negotiate_transfer_params_req(
730 	uint8_t instance_id,
731 	const struct pldm_base_negotiate_transfer_params_req *req,
732 	struct pldm_msg *msg, size_t payload_length)
733 {
734 	PLDM_MSGBUF_DEFINE_P(buf);
735 	int rc;
736 
737 	if (req == NULL || msg == NULL) {
738 		return -EINVAL;
739 	}
740 
741 	struct pldm_header_info header = { 0 };
742 	header.instance = instance_id;
743 	header.msg_type = PLDM_REQUEST;
744 	header.pldm_type = PLDM_BASE;
745 	header.command = PLDM_NEGOTIATE_TRANSFER_PARAMETERS;
746 
747 	rc = pack_pldm_header_errno(&header, &msg->hdr);
748 	if (rc) {
749 		return rc;
750 	}
751 
752 	rc = pldm_msgbuf_init_errno(
753 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES,
754 		msg->payload, payload_length);
755 	if (rc) {
756 		return rc;
757 	}
758 
759 	pldm_msgbuf_insert(buf, req->requester_part_size);
760 	rc = pldm_msgbuf_insert_array(
761 		buf, sizeof(req->requester_protocol_support),
762 		(uint8_t *)req->requester_protocol_support,
763 		sizeof(req->requester_protocol_support));
764 	if (rc) {
765 		return pldm_msgbuf_discard(buf, rc);
766 	}
767 
768 	return pldm_msgbuf_complete(buf);
769 }
770 
771 LIBPLDM_ABI_TESTING
decode_pldm_base_negotiate_transfer_params_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_base_negotiate_transfer_params_resp * resp)772 int decode_pldm_base_negotiate_transfer_params_resp(
773 	const struct pldm_msg *msg, size_t payload_length,
774 	struct pldm_base_negotiate_transfer_params_resp *resp)
775 {
776 	PLDM_MSGBUF_DEFINE_P(buf);
777 	int rc;
778 
779 	if (msg == NULL || resp == NULL) {
780 		return -EINVAL;
781 	}
782 
783 	rc = pldm_msg_has_error(msg, payload_length);
784 
785 	if (rc) {
786 		resp->completion_code = rc;
787 		return 0;
788 	}
789 
790 	rc = pldm_msgbuf_init_errno(
791 		buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES,
792 		msg->payload, payload_length);
793 	if (rc) {
794 		return rc;
795 	}
796 
797 	pldm_msgbuf_extract(buf, resp->completion_code);
798 	pldm_msgbuf_extract(buf, resp->responder_part_size);
799 	rc = pldm_msgbuf_extract_array(
800 		buf, sizeof(resp->responder_protocol_support),
801 		(uint8_t *)resp->responder_protocol_support,
802 		sizeof(resp->responder_protocol_support));
803 	if (rc) {
804 		return pldm_msgbuf_discard(buf, rc);
805 	}
806 
807 	return pldm_msgbuf_complete_consumed(buf);
808 }
809