1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 #include "api.h" 3 #include "dsp/base.h" 4 5 #include <assert.h> 6 #include <libpldm/base.h> 7 #include <libpldm/pldm_types.h> 8 9 #include <endian.h> 10 #include <errno.h> 11 #include <stdint.h> 12 #include <string.h> 13 14 int pack_pldm_header_errno(const struct pldm_header_info *hdr, 15 struct pldm_msg_hdr *msg) 16 { 17 if (msg == NULL || hdr == NULL) { 18 return -EINVAL; 19 } 20 21 if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST && 22 hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) { 23 return -EINVAL; 24 } 25 26 if (hdr->instance > PLDM_INSTANCE_MAX) { 27 return -EINVAL; 28 } 29 30 if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) { 31 return -ENOMSG; 32 } 33 34 uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0; 35 36 if (hdr->msg_type == PLDM_RESPONSE) { 37 msg->request = PLDM_RESPONSE; 38 } else if (hdr->msg_type == PLDM_REQUEST || 39 hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) { 40 msg->request = PLDM_REQUEST; 41 } 42 msg->datagram = datagram; 43 msg->reserved = 0; 44 msg->instance_id = hdr->instance; 45 msg->header_ver = PLDM_CURRENT_VERSION; 46 msg->type = hdr->pldm_type; 47 msg->command = hdr->command; 48 49 return 0; 50 } 51 52 int unpack_pldm_header_errno(const struct pldm_msg_hdr *msg, 53 struct pldm_header_info *hdr) 54 { 55 if (msg == NULL) { 56 return -EINVAL; 57 } 58 59 if (msg->request == PLDM_RESPONSE) { 60 hdr->msg_type = PLDM_RESPONSE; 61 } else { 62 hdr->msg_type = msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY : 63 PLDM_REQUEST; 64 } 65 66 hdr->instance = msg->instance_id; 67 hdr->pldm_type = msg->type; 68 hdr->command = msg->command; 69 70 return 0; 71 } 72 73 LIBPLDM_ABI_STABLE 74 uint8_t pack_pldm_header(const struct pldm_header_info *hdr, 75 struct pldm_msg_hdr *msg) 76 { 77 enum pldm_completion_codes cc; 78 int rc; 79 80 rc = pack_pldm_header_errno(hdr, msg); 81 if (!rc) { 82 return PLDM_SUCCESS; 83 } 84 85 cc = pldm_xlate_errno(rc); 86 assert(cc < UINT8_MAX); 87 if (cc > UINT8_MAX) { 88 static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error"); 89 return PLDM_ERROR; 90 } 91 92 return cc; 93 } 94 95 LIBPLDM_ABI_STABLE 96 uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg, 97 struct pldm_header_info *hdr) 98 { 99 enum pldm_completion_codes cc; 100 int rc; 101 102 rc = unpack_pldm_header_errno(msg, hdr); 103 if (!rc) { 104 return PLDM_SUCCESS; 105 } 106 107 cc = pldm_xlate_errno(rc); 108 assert(cc < UINT8_MAX); 109 if (cc > UINT8_MAX) { 110 static_assert(PLDM_ERROR < UINT8_MAX, "Unable to report error"); 111 return PLDM_ERROR; 112 } 113 114 return cc; 115 } 116 117 LIBPLDM_ABI_STABLE 118 bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req, 119 const struct pldm_msg_hdr *resp) 120 { 121 return req->instance_id == resp->instance_id && req->request && 122 !resp->request && req->type == resp->type && 123 req->command == resp->command; 124 } 125 126 LIBPLDM_ABI_STABLE 127 int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg) 128 { 129 if (msg == NULL) { 130 return PLDM_ERROR_INVALID_DATA; 131 } 132 133 struct pldm_header_info header = { 0 }; 134 header.instance = instance_id; 135 header.msg_type = PLDM_REQUEST; 136 header.command = PLDM_GET_PLDM_TYPES; 137 138 return pack_pldm_header(&header, &(msg->hdr)); 139 } 140 141 LIBPLDM_ABI_STABLE 142 int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version, 143 struct pldm_msg *msg) 144 { 145 if (msg == NULL) { 146 return PLDM_ERROR_INVALID_DATA; 147 } 148 149 struct pldm_header_info header = { 0 }; 150 header.instance = instance_id; 151 header.msg_type = PLDM_REQUEST; 152 header.command = PLDM_GET_PLDM_COMMANDS; 153 154 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 155 if (rc != PLDM_SUCCESS) { 156 return rc; 157 } 158 159 struct pldm_get_commands_req *request = 160 (struct pldm_get_commands_req *)msg->payload; 161 162 request->type = type; 163 request->version = version; 164 165 return PLDM_SUCCESS; 166 } 167 168 LIBPLDM_ABI_STABLE 169 int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code, 170 const bitfield8_t *types, struct pldm_msg *msg) 171 { 172 if (msg == NULL) { 173 return PLDM_ERROR_INVALID_DATA; 174 } 175 176 struct pldm_header_info header = { 0 }; 177 header.instance = instance_id; 178 header.msg_type = PLDM_RESPONSE; 179 header.command = PLDM_GET_PLDM_TYPES; 180 181 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 182 if (rc != PLDM_SUCCESS) { 183 return rc; 184 } 185 186 struct pldm_get_types_resp *response = 187 (struct pldm_get_types_resp *)msg->payload; 188 response->completion_code = completion_code; 189 if (response->completion_code == PLDM_SUCCESS) { 190 if (types == NULL) { 191 return PLDM_ERROR_INVALID_DATA; 192 } 193 memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8); 194 } 195 196 return PLDM_SUCCESS; 197 } 198 199 LIBPLDM_ABI_STABLE 200 int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length, 201 uint8_t *type, ver32_t *version) 202 { 203 if (msg == NULL || type == NULL || version == NULL) { 204 return PLDM_ERROR_INVALID_DATA; 205 } 206 207 if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) { 208 return PLDM_ERROR_INVALID_LENGTH; 209 } 210 211 struct pldm_get_commands_req *request = 212 (struct pldm_get_commands_req *)msg->payload; 213 *type = request->type; 214 *version = request->version; 215 return PLDM_SUCCESS; 216 } 217 218 LIBPLDM_ABI_STABLE 219 int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code, 220 const bitfield8_t *commands, struct pldm_msg *msg) 221 { 222 if (msg == NULL) { 223 return PLDM_ERROR_INVALID_DATA; 224 } 225 226 struct pldm_header_info header = { 0 }; 227 header.instance = instance_id; 228 header.msg_type = PLDM_RESPONSE; 229 header.command = PLDM_GET_PLDM_COMMANDS; 230 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 231 if (rc != PLDM_SUCCESS) { 232 return rc; 233 } 234 235 struct pldm_get_commands_resp *response = 236 (struct pldm_get_commands_resp *)msg->payload; 237 response->completion_code = completion_code; 238 if (response->completion_code == PLDM_SUCCESS) { 239 if (commands == NULL) { 240 return PLDM_ERROR_INVALID_DATA; 241 } 242 memcpy(response->commands, &(commands->byte), 243 PLDM_MAX_CMDS_PER_TYPE / 8); 244 } 245 246 return PLDM_SUCCESS; 247 } 248 249 LIBPLDM_ABI_STABLE 250 int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length, 251 uint8_t *completion_code, bitfield8_t *types) 252 { 253 if (msg == NULL || types == NULL || completion_code == NULL) { 254 return PLDM_ERROR_INVALID_DATA; 255 } 256 257 *completion_code = msg->payload[0]; 258 if (PLDM_SUCCESS != *completion_code) { 259 return PLDM_SUCCESS; 260 } 261 262 if (payload_length != PLDM_GET_TYPES_RESP_BYTES) { 263 return PLDM_ERROR_INVALID_LENGTH; 264 } 265 266 struct pldm_get_types_resp *response = 267 (struct pldm_get_types_resp *)msg->payload; 268 269 memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8); 270 271 return PLDM_SUCCESS; 272 } 273 274 LIBPLDM_ABI_STABLE 275 int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length, 276 uint8_t *completion_code, bitfield8_t *commands) 277 { 278 if (msg == NULL || commands == NULL || completion_code == NULL) { 279 return PLDM_ERROR_INVALID_DATA; 280 } 281 282 *completion_code = msg->payload[0]; 283 if (PLDM_SUCCESS != *completion_code) { 284 return PLDM_SUCCESS; 285 } 286 287 if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) { 288 return PLDM_ERROR_INVALID_LENGTH; 289 } 290 291 struct pldm_get_commands_resp *response = 292 (struct pldm_get_commands_resp *)msg->payload; 293 294 memcpy(&(commands->byte), response->commands, 295 PLDM_MAX_CMDS_PER_TYPE / 8); 296 297 return PLDM_SUCCESS; 298 } 299 300 LIBPLDM_ABI_STABLE 301 int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle, 302 uint8_t transfer_opflag, uint8_t type, 303 struct pldm_msg *msg) 304 { 305 if (NULL == msg) { 306 return PLDM_ERROR_INVALID_DATA; 307 } 308 309 struct pldm_header_info header = { 0 }; 310 header.msg_type = PLDM_REQUEST; 311 header.instance = instance_id; 312 header.pldm_type = PLDM_BASE; 313 header.command = PLDM_GET_PLDM_VERSION; 314 315 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 316 if (rc != PLDM_SUCCESS) { 317 return rc; 318 } 319 320 struct pldm_get_version_req *request = 321 (struct pldm_get_version_req *)msg->payload; 322 transfer_handle = htole32(transfer_handle); 323 request->transfer_handle = transfer_handle; 324 request->transfer_opflag = transfer_opflag; 325 request->type = type; 326 327 return PLDM_SUCCESS; 328 } 329 330 LIBPLDM_ABI_STABLE 331 int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code, 332 uint32_t next_transfer_handle, 333 uint8_t transfer_flag, const ver32_t *version_data, 334 size_t version_size, struct pldm_msg *msg) 335 { 336 if (NULL == msg) { 337 return PLDM_ERROR_INVALID_DATA; 338 } 339 340 struct pldm_header_info header = { 0 }; 341 header.msg_type = PLDM_RESPONSE; 342 header.instance = instance_id; 343 header.pldm_type = PLDM_BASE; 344 header.command = PLDM_GET_PLDM_VERSION; 345 346 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 347 if (rc != PLDM_SUCCESS) { 348 return rc; 349 } 350 351 struct pldm_get_version_resp *response = 352 (struct pldm_get_version_resp *)msg->payload; 353 response->completion_code = completion_code; 354 if (response->completion_code == PLDM_SUCCESS) { 355 response->next_transfer_handle = htole32(next_transfer_handle); 356 response->transfer_flag = transfer_flag; 357 memcpy(response->version_data, (uint8_t *)version_data, 358 version_size); 359 } 360 return PLDM_SUCCESS; 361 } 362 363 LIBPLDM_ABI_STABLE 364 int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length, 365 uint32_t *transfer_handle, uint8_t *transfer_opflag, 366 uint8_t *type) 367 { 368 if (payload_length != PLDM_GET_VERSION_REQ_BYTES) { 369 return PLDM_ERROR_INVALID_LENGTH; 370 } 371 372 struct pldm_get_version_req *request = 373 (struct pldm_get_version_req *)msg->payload; 374 *transfer_handle = le32toh(request->transfer_handle); 375 *transfer_opflag = request->transfer_opflag; 376 *type = request->type; 377 return PLDM_SUCCESS; 378 } 379 380 LIBPLDM_ABI_STABLE 381 int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length, 382 uint8_t *completion_code, 383 uint32_t *next_transfer_handle, 384 uint8_t *transfer_flag, ver32_t *version) 385 { 386 if (msg == NULL || next_transfer_handle == NULL || 387 transfer_flag == NULL || completion_code == NULL) { 388 return PLDM_ERROR_INVALID_DATA; 389 } 390 391 *completion_code = msg->payload[0]; 392 if (PLDM_SUCCESS != *completion_code) { 393 return PLDM_SUCCESS; 394 } 395 396 if (payload_length < PLDM_GET_VERSION_RESP_BYTES) { 397 return PLDM_ERROR_INVALID_LENGTH; 398 } 399 400 struct pldm_get_version_resp *response = 401 (struct pldm_get_version_resp *)msg->payload; 402 403 *next_transfer_handle = le32toh(response->next_transfer_handle); 404 *transfer_flag = response->transfer_flag; 405 memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t)); 406 407 return PLDM_SUCCESS; 408 } 409 410 LIBPLDM_ABI_STABLE 411 int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg) 412 { 413 if (msg == NULL) { 414 return PLDM_ERROR_INVALID_DATA; 415 } 416 417 struct pldm_header_info header = { 0 }; 418 header.instance = instance_id; 419 header.msg_type = PLDM_REQUEST; 420 header.command = PLDM_GET_TID; 421 422 return pack_pldm_header(&header, &(msg->hdr)); 423 } 424 425 LIBPLDM_ABI_STABLE 426 int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code, 427 uint8_t tid, struct pldm_msg *msg) 428 { 429 if (msg == NULL) { 430 return PLDM_ERROR_INVALID_DATA; 431 } 432 433 struct pldm_header_info header = { 0 }; 434 header.instance = instance_id; 435 header.msg_type = PLDM_RESPONSE; 436 header.command = PLDM_GET_TID; 437 438 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 439 if (rc != PLDM_SUCCESS) { 440 return rc; 441 } 442 443 struct pldm_get_tid_resp *response = 444 (struct pldm_get_tid_resp *)msg->payload; 445 response->completion_code = completion_code; 446 response->tid = tid; 447 448 return PLDM_SUCCESS; 449 } 450 451 LIBPLDM_ABI_STABLE 452 int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length, 453 uint8_t *completion_code, uint8_t *tid) 454 { 455 if (msg == NULL || tid == NULL || completion_code == NULL) { 456 return PLDM_ERROR_INVALID_DATA; 457 } 458 459 *completion_code = msg->payload[0]; 460 if (PLDM_SUCCESS != *completion_code) { 461 return PLDM_SUCCESS; 462 } 463 464 if (payload_length != PLDM_GET_TID_RESP_BYTES) { 465 return PLDM_ERROR_INVALID_LENGTH; 466 } 467 468 struct pldm_get_tid_resp *response = 469 (struct pldm_get_tid_resp *)msg->payload; 470 471 *tid = response->tid; 472 473 return PLDM_SUCCESS; 474 } 475 476 LIBPLDM_ABI_STABLE 477 int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg) 478 { 479 if (msg == NULL) { 480 return PLDM_ERROR_INVALID_DATA; 481 } 482 483 if (tid == 0x0 || tid == 0xff) { 484 return PLDM_ERROR_INVALID_DATA; 485 } 486 487 struct pldm_header_info header = { 0 }; 488 header.instance = instance_id; 489 header.msg_type = PLDM_REQUEST; 490 header.command = PLDM_SET_TID; 491 492 uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 493 if (rc != PLDM_SUCCESS) { 494 return rc; 495 } 496 497 struct pldm_set_tid_req *request = 498 (struct pldm_set_tid_req *)msg->payload; 499 request->tid = tid; 500 501 return PLDM_SUCCESS; 502 } 503 504 LIBPLDM_ABI_STABLE 505 int decode_multipart_receive_req(const struct pldm_msg *msg, 506 size_t payload_length, uint8_t *pldm_type, 507 uint8_t *transfer_opflag, 508 uint32_t *transfer_ctx, 509 uint32_t *transfer_handle, 510 uint32_t *section_offset, 511 uint32_t *section_length) 512 { 513 if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL || 514 transfer_ctx == NULL || transfer_handle == NULL || 515 section_offset == NULL || section_length == NULL) { 516 return PLDM_ERROR_INVALID_DATA; 517 } 518 519 if (payload_length != PLDM_MULTIPART_RECEIVE_REQ_BYTES) { 520 return PLDM_ERROR_INVALID_LENGTH; 521 } 522 523 struct pldm_multipart_receive_req *request = 524 (struct pldm_multipart_receive_req *)msg->payload; 525 526 if (request->pldm_type != PLDM_BASE) { 527 return PLDM_ERROR_INVALID_PLDM_TYPE; 528 } 529 530 // Any enum value above PLDM_XFER_CURRENT_PART is invalid. 531 if (request->transfer_opflag > PLDM_XFER_CURRENT_PART) { 532 return PLDM_INVALID_TRANSFER_OPERATION_FLAG; 533 } 534 535 // A section offset of 0 is only valid on FIRST_PART or COMPLETE Xfers. 536 uint32_t sec_offset = le32toh(request->section_offset); 537 if (sec_offset == 0 && 538 (request->transfer_opflag != PLDM_XFER_FIRST_PART && 539 request->transfer_opflag != PLDM_XFER_COMPLETE)) { 540 return PLDM_ERROR_INVALID_DATA; 541 } 542 543 uint32_t handle = le32toh(request->transfer_handle); 544 if (handle == 0 && request->transfer_opflag != PLDM_XFER_COMPLETE) { 545 return PLDM_ERROR_INVALID_DATA; 546 } 547 548 *pldm_type = request->pldm_type; 549 *transfer_opflag = request->transfer_opflag; 550 *transfer_ctx = request->transfer_ctx; 551 *transfer_handle = handle; 552 *section_offset = sec_offset; 553 *section_length = le32toh(request->section_length); 554 555 return PLDM_SUCCESS; 556 } 557 558 LIBPLDM_ABI_STABLE 559 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command, 560 uint8_t cc, struct pldm_msg *msg) 561 { 562 if (msg == NULL) { 563 return PLDM_ERROR_INVALID_DATA; 564 } 565 566 struct pldm_header_info header = { 0 }; 567 header.instance = instance_id; 568 header.msg_type = PLDM_RESPONSE; 569 header.pldm_type = type; 570 header.command = command; 571 572 uint8_t rc = pack_pldm_header(&header, &msg->hdr); 573 if (rc != PLDM_SUCCESS) { 574 return rc; 575 } 576 577 msg->payload[0] = cc; 578 579 return PLDM_SUCCESS; 580 } 581 582 LIBPLDM_ABI_STABLE 583 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id, 584 uint8_t pldm_type, uint8_t command, 585 struct pldm_msg *msg) 586 { 587 if (msg == NULL) { 588 return PLDM_ERROR_INVALID_DATA; 589 } 590 591 struct pldm_header_info header = { 0 }; 592 header.msg_type = msg_type; 593 header.instance = instance_id; 594 header.pldm_type = pldm_type; 595 header.command = command; 596 return pack_pldm_header(&header, &(msg->hdr)); 597 } 598