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