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