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_RO_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 PLDM_MSGBUF_RO_DEFINE_P(buf);
537 int rc;
538
539 if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
540 transfer_ctx == NULL || transfer_handle == NULL ||
541 section_offset == NULL || section_length == NULL) {
542 return PLDM_ERROR_INVALID_DATA;
543 }
544
545 rc = pldm_msgbuf_init_errno(buf, PLDM_MULTIPART_RECEIVE_REQ_BYTES,
546 msg->payload, payload_length);
547 if (rc) {
548 return pldm_xlate_errno(rc);
549 }
550
551 pldm_msgbuf_extract_p(buf, pldm_type);
552 pldm_msgbuf_extract_p(buf, transfer_opflag);
553 pldm_msgbuf_extract_p(buf, transfer_ctx);
554 pldm_msgbuf_extract_p(buf, transfer_handle);
555 pldm_msgbuf_extract_p(buf, section_offset);
556 pldm_msgbuf_extract_p(buf, section_length);
557
558 rc = pldm_msgbuf_complete_consumed(buf);
559 if (rc) {
560 return pldm_xlate_errno(rc);
561 }
562
563 if (*pldm_type != PLDM_BASE && *pldm_type != PLDM_FILE) {
564 return PLDM_ERROR_INVALID_PLDM_TYPE;
565 }
566
567 // Any enum value above PLDM_XFER_CURRENT_PART is invalid.
568 if (*transfer_opflag > PLDM_XFER_CURRENT_PART) {
569 return PLDM_ERROR_UNEXPECTED_TRANSFER_FLAG_OPERATION;
570 }
571
572 // By DSP0240 v1.2.0, section 9.6.5, Table 17, transfer handle can be 0 only
573 // if the transfer flag is one of XFER_FIRST_PART, XFER_COMPLETE or
574 // XFER_ABORT. In addition, it must be allowed in PLDM_XFER_CURRENT_PART as
575 // this may be used to retry the first part, in which case the transfer handle
576 // must again be 0. Therefore, the only operation for which it cannot be 0 is
577 // PLDM_XFER_NEXT_PART.
578 if ((*transfer_handle == 0) &&
579 (*transfer_opflag == PLDM_XFER_NEXT_PART)) {
580 return PLDM_ERROR_INVALID_DATA;
581 }
582
583 return PLDM_SUCCESS;
584 }
585
586 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)587 int encode_pldm_base_multipart_receive_req(
588 uint8_t instance_id, const struct pldm_base_multipart_receive_req *req,
589 struct pldm_msg *msg, size_t *payload_length)
590 {
591 PLDM_MSGBUF_RW_DEFINE_P(buf);
592 int rc;
593
594 if (req == NULL || msg == NULL || payload_length == NULL) {
595 return -EINVAL;
596 }
597
598 struct pldm_header_info header = { 0 };
599 header.instance = instance_id;
600 header.msg_type = PLDM_REQUEST;
601 header.pldm_type = PLDM_BASE;
602 header.command = PLDM_MULTIPART_RECEIVE;
603
604 rc = pack_pldm_header_errno(&header, &msg->hdr);
605 if (rc) {
606 return rc;
607 }
608
609 rc = pldm_msgbuf_init_errno(buf, PLDM_MULTIPART_RECEIVE_REQ_BYTES,
610 msg->payload, *payload_length);
611 if (rc) {
612 return rc;
613 }
614
615 pldm_msgbuf_insert(buf, req->pldm_type);
616 pldm_msgbuf_insert(buf, req->transfer_opflag);
617 pldm_msgbuf_insert(buf, req->transfer_ctx);
618 pldm_msgbuf_insert(buf, req->transfer_handle);
619 pldm_msgbuf_insert(buf, req->section_offset);
620 pldm_msgbuf_insert(buf, req->section_length);
621
622 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
623 }
624
625 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)626 int decode_pldm_base_multipart_receive_resp(
627 const struct pldm_msg *msg, size_t payload_length,
628 struct pldm_base_multipart_receive_resp *resp,
629 uint32_t *data_integrity_checksum)
630 {
631 PLDM_MSGBUF_RO_DEFINE_P(buf);
632 int rc;
633
634 if (msg == NULL || resp == NULL || data_integrity_checksum == NULL) {
635 return -EINVAL;
636 }
637
638 rc = pldm_msg_has_error(msg, payload_length);
639
640 if (rc) {
641 resp->completion_code = rc;
642 return 0;
643 }
644
645 rc = pldm_msgbuf_init_errno(buf,
646 PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
647 msg->payload, payload_length);
648 if (rc) {
649 return rc;
650 }
651
652 pldm_msgbuf_extract(buf, resp->completion_code);
653 rc = pldm_msgbuf_extract(buf, resp->transfer_flag);
654 if (rc) {
655 return pldm_msgbuf_discard(buf, rc);
656 }
657 pldm_msgbuf_extract(buf, resp->next_transfer_handle);
658
659 rc = pldm_msgbuf_extract_uint32_to_size(buf, resp->data.length);
660 if (rc) {
661 return pldm_msgbuf_discard(buf, rc);
662 }
663
664 if (resp->data.length > 0) {
665 resp->data.ptr = NULL;
666 pldm_msgbuf_span_required(buf, resp->data.length,
667 (const void **)&resp->data.ptr);
668 }
669
670 if (resp->transfer_flag !=
671 PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_ACK_COMPLETION) {
672 pldm_msgbuf_extract_p(buf, data_integrity_checksum);
673 }
674
675 return pldm_msgbuf_complete_consumed(buf);
676 }
677
678 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)679 int encode_base_multipart_receive_resp(
680 uint8_t instance_id,
681 const struct pldm_base_multipart_receive_resp *resp, uint32_t checksum,
682 struct pldm_msg *msg, size_t *payload_length)
683 {
684 PLDM_MSGBUF_RW_DEFINE_P(buf);
685 int rc;
686
687 if (!msg || !resp || !payload_length) {
688 return -EINVAL;
689 }
690
691 if ((resp->data.length > 0) && !resp->data.ptr) {
692 return -EINVAL;
693 }
694
695 struct pldm_header_info header = { 0 };
696 header.instance = instance_id;
697 header.msg_type = PLDM_RESPONSE;
698 header.pldm_type = PLDM_BASE;
699 header.command = PLDM_MULTIPART_RECEIVE;
700
701 rc = pack_pldm_header_errno(&header, &msg->hdr);
702 if (rc) {
703 return rc;
704 }
705
706 rc = pldm_msgbuf_init_errno(buf,
707 PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES,
708 msg->payload, *payload_length);
709 if (rc) {
710 return rc;
711 }
712
713 pldm_msgbuf_insert(buf, resp->completion_code);
714 if (resp->completion_code != PLDM_SUCCESS) {
715 // Return without encoding the rest of the field
716 return pldm_msgbuf_complete_used(buf, *payload_length,
717 payload_length);
718 }
719
720 pldm_msgbuf_insert(buf, resp->transfer_flag);
721 pldm_msgbuf_insert(buf, resp->next_transfer_handle);
722
723 pldm_msgbuf_insert_uint32(buf, resp->data.length);
724 if (resp->data.length == 0) {
725 // Return without encoding data payload
726 return pldm_msgbuf_complete_used(buf, *payload_length,
727 payload_length);
728 }
729
730 rc = pldm_msgbuf_insert_array(buf, resp->data.length, resp->data.ptr,
731 resp->data.length);
732 if (rc) {
733 return pldm_msgbuf_discard(buf, rc);
734 }
735
736 // Checksum is present for all data parts except when response transfer flag is
737 // ACKNOWLEDGE_COMPLETION
738 if (resp->transfer_flag !=
739 PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_ACK_COMPLETION) {
740 pldm_msgbuf_insert(buf, checksum);
741 }
742
743 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
744 }
745
746 LIBPLDM_ABI_STABLE
encode_cc_only_resp(uint8_t instance_id,uint8_t type,uint8_t command,uint8_t cc,struct pldm_msg * msg)747 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
748 uint8_t cc, struct pldm_msg *msg)
749 {
750 if (msg == NULL) {
751 return PLDM_ERROR_INVALID_DATA;
752 }
753
754 struct pldm_header_info header = { 0 };
755 header.instance = instance_id;
756 header.msg_type = PLDM_RESPONSE;
757 header.pldm_type = type;
758 header.command = command;
759
760 uint8_t rc = pack_pldm_header(&header, &msg->hdr);
761 if (rc != PLDM_SUCCESS) {
762 return rc;
763 }
764
765 msg->payload[0] = cc;
766
767 return PLDM_SUCCESS;
768 }
769
encode_pldm_header_only_errno(uint8_t msg_type,uint8_t instance_id,uint8_t pldm_type,uint8_t command,struct pldm_msg * msg)770 int encode_pldm_header_only_errno(uint8_t msg_type, uint8_t instance_id,
771 uint8_t pldm_type, uint8_t command,
772 struct pldm_msg *msg)
773 {
774 if (msg == NULL) {
775 return -EINVAL;
776 }
777
778 struct pldm_header_info header = { 0 };
779 header.msg_type = msg_type;
780 header.instance = instance_id;
781 header.pldm_type = pldm_type;
782 header.command = command;
783 return pack_pldm_header_errno(&header, &(msg->hdr));
784 }
785
786 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)787 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
788 uint8_t pldm_type, uint8_t command,
789 struct pldm_msg *msg)
790 {
791 int rc = encode_pldm_header_only_errno(msg_type, instance_id, pldm_type,
792 command, msg);
793 if (rc) {
794 return pldm_xlate_errno(rc);
795 }
796 return PLDM_SUCCESS;
797 }
798
799 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)800 int encode_pldm_base_negotiate_transfer_params_req(
801 uint8_t instance_id,
802 const struct pldm_base_negotiate_transfer_params_req *req,
803 struct pldm_msg *msg, size_t *payload_length)
804 {
805 PLDM_MSGBUF_RW_DEFINE_P(buf);
806 int rc;
807
808 if (req == NULL || msg == NULL || payload_length == NULL) {
809 return -EINVAL;
810 }
811
812 struct pldm_header_info header = { 0 };
813 header.instance = instance_id;
814 header.msg_type = PLDM_REQUEST;
815 header.pldm_type = PLDM_BASE;
816 header.command = PLDM_NEGOTIATE_TRANSFER_PARAMETERS;
817
818 rc = pack_pldm_header_errno(&header, &msg->hdr);
819 if (rc) {
820 return rc;
821 }
822
823 rc = pldm_msgbuf_init_errno(
824 buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES,
825 msg->payload, *payload_length);
826 if (rc) {
827 return rc;
828 }
829
830 pldm_msgbuf_insert(buf, req->requester_part_size);
831 rc = pldm_msgbuf_insert_array(
832 buf, sizeof(req->requester_protocol_support),
833 (uint8_t *)req->requester_protocol_support,
834 sizeof(req->requester_protocol_support));
835 if (rc) {
836 return pldm_msgbuf_discard(buf, rc);
837 }
838
839 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
840 }
841
842 #define PLDM_BASE_MIN_PART_SIZE 256
843
844 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)845 int encode_pldm_base_negotiate_transfer_params_resp(
846 uint8_t instance_id,
847 const struct pldm_base_negotiate_transfer_params_resp *resp,
848 struct pldm_msg *msg, size_t *payload_length)
849 {
850 PLDM_MSGBUF_RW_DEFINE_P(buf);
851 int rc;
852
853 if (resp == NULL || msg == NULL) {
854 return -EINVAL;
855 }
856
857 if (resp->responder_part_size < PLDM_BASE_MIN_PART_SIZE) {
858 return -EINVAL;
859 }
860
861 struct pldm_header_info header = { 0 };
862 header.instance = instance_id;
863 header.msg_type = PLDM_RESPONSE;
864 header.pldm_type = PLDM_BASE;
865 header.command = PLDM_NEGOTIATE_TRANSFER_PARAMETERS;
866
867 rc = pack_pldm_header_errno(&header, &msg->hdr);
868 if (rc) {
869 return rc;
870 }
871
872 rc = pldm_msgbuf_init_errno(
873 buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES,
874 msg->payload, *payload_length);
875 if (rc) {
876 return rc;
877 }
878
879 pldm_msgbuf_insert(buf, resp->completion_code);
880 pldm_msgbuf_insert(buf, resp->responder_part_size);
881 rc = pldm_msgbuf_insert_array(
882 buf, sizeof(resp->responder_protocol_support),
883 (uint8_t *)resp->responder_protocol_support,
884 sizeof(resp->responder_protocol_support));
885 if (rc) {
886 return pldm_msgbuf_discard(buf, rc);
887 }
888
889 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
890 }
891
892 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)893 int decode_pldm_base_negotiate_transfer_params_req(
894 const struct pldm_msg *msg, size_t payload_length,
895 struct pldm_base_negotiate_transfer_params_req *req)
896 {
897 PLDM_MSGBUF_RO_DEFINE_P(buf);
898 int rc;
899
900 if (msg == NULL || req == NULL) {
901 return -EINVAL;
902 }
903
904 rc = pldm_msgbuf_init_errno(
905 buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES,
906 msg->payload, payload_length);
907 if (rc) {
908 return rc;
909 }
910
911 pldm_msgbuf_extract(buf, req->requester_part_size);
912
913 rc = pldm_msgbuf_extract_array(
914 buf, sizeof(req->requester_protocol_support),
915 (uint8_t *)req->requester_protocol_support,
916 sizeof(req->requester_protocol_support));
917 if (rc) {
918 return pldm_msgbuf_discard(buf, rc);
919 }
920
921 return pldm_msgbuf_complete_consumed(buf);
922 }
923
924 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)925 int decode_pldm_base_negotiate_transfer_params_resp(
926 const struct pldm_msg *msg, size_t payload_length,
927 struct pldm_base_negotiate_transfer_params_resp *resp)
928 {
929 PLDM_MSGBUF_RO_DEFINE_P(buf);
930 int rc;
931
932 if (msg == NULL || resp == NULL) {
933 return -EINVAL;
934 }
935
936 rc = pldm_msg_has_error(msg, payload_length);
937
938 if (rc) {
939 resp->completion_code = rc;
940 return 0;
941 }
942
943 rc = pldm_msgbuf_init_errno(
944 buf, PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES,
945 msg->payload, payload_length);
946 if (rc) {
947 return rc;
948 }
949
950 pldm_msgbuf_extract(buf, resp->completion_code);
951 pldm_msgbuf_extract(buf, resp->responder_part_size);
952 rc = pldm_msgbuf_extract_array(
953 buf, sizeof(resp->responder_protocol_support),
954 (uint8_t *)resp->responder_protocol_support,
955 sizeof(resp->responder_protocol_support));
956 if (rc) {
957 return pldm_msgbuf_discard(buf, rc);
958 }
959
960 return pldm_msgbuf_complete_consumed(buf);
961 }
962