1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 #include <stdint.h> 3 #include <stdbool.h> 4 #include <string.h> 5 #include <stdlib.h> 6 7 #include <libpldm/pldm.h> 8 #include <libpldm/firmware_update.h> 9 #include <libpldm/firmware_fd.h> 10 #include <libpldm/utils.h> 11 #include <compiler.h> 12 #include <msgbuf.h> 13 14 #include "fd-internal.h" 15 16 /* FD_T1 Update mode idle timeout, 120 seconds (range [60s, 120s])*/ 17 static const pldm_fd_time_t DEFAULT_FD_T1_TIMEOUT = 120000; 18 19 /* FD_T2 "Retry request for firmware data", 1 second (range [1s, 5s]) */ 20 static const pldm_fd_time_t DEFAULT_FD_T2_RETRY_TIME = 1000; 21 22 static const uint8_t INSTANCE_ID_COUNT = 32; 23 static const uint8_t PROGRESS_PERCENT_NOT_SUPPORTED = 101; 24 25 #define PLDM_FD_VERSIONS_COUNT 2 26 static const uint32_t PLDM_FD_VERSIONS[PLDM_FD_VERSIONS_COUNT] = { 27 /* Only PLDM Firmware 1.1.0 is current implemented. */ 28 0xf1f1f000, 29 /* CRC. Calculated with python: 30 hex(crccheck.crc.Crc32.calc(struct.pack('<I', 0xf1f1f000))) 31 */ 32 0x539dbeba, 33 }; 34 const bitfield8_t PLDM_FD_COMMANDS[32] = { 35 // 0x00..0x07 36 { .byte = (1 << PLDM_QUERY_DEVICE_IDENTIFIERS | 37 1 << PLDM_GET_FIRMWARE_PARAMETERS) }, 38 { 0 }, 39 // 0x10..0x17 40 { .byte = (1u << PLDM_REQUEST_UPDATE | 1u << PLDM_PASS_COMPONENT_TABLE | 41 1u << PLDM_UPDATE_COMPONENT) >> 42 0x10 }, 43 // 0x18..0x1f 44 { 45 .byte = (1u << PLDM_ACTIVATE_FIRMWARE | 1u << PLDM_GET_STATUS | 46 1u << PLDM_CANCEL_UPDATE_COMPONENT | 47 1u << PLDM_CANCEL_UPDATE) >> 48 0x18, 49 }, 50 }; 51 52 /* Ensure that public definition is kept updated */ 53 static_assert(alignof(struct pldm_fd) == PLDM_ALIGNOF_PLDM_FD, 54 "PLDM_ALIGNOF_PLDM_FD wrong"); 55 56 /* Maybe called with success or failure completion codes, though 57 * success only makes sense for responses without a body. 58 * Returns 0 or negative errno. */ 59 LIBPLDM_CC_NONNULL 60 static int pldm_fd_reply_cc(uint8_t ccode, 61 const struct pldm_header_info *req_hdr, 62 struct pldm_msg *resp, size_t *resp_payload_len) 63 { 64 int status; 65 66 /* 1 byte completion code */ 67 if (*resp_payload_len < 1) { 68 return -EOVERFLOW; 69 } 70 *resp_payload_len = 1; 71 72 status = encode_cc_only_resp(req_hdr->instance, PLDM_FWUP, 73 req_hdr->command, ccode, resp); 74 if (status != PLDM_SUCCESS) { 75 return -EINVAL; 76 } 77 return 0; 78 } 79 80 /* Must be called with a negative errno. 81 * Returns 0 or negative errno. */ 82 LIBPLDM_CC_NONNULL 83 static int pldm_fd_reply_errno(int err, const struct pldm_header_info *req_hdr, 84 struct pldm_msg *resp, size_t *resp_payload_len) 85 { 86 uint8_t ccode = PLDM_ERROR; 87 88 assert(err < 0); 89 switch (err) { 90 case -EINVAL: 91 // internal error, shouldn't occur. 92 ccode = PLDM_ERROR; 93 break; 94 case -EPROTO: 95 // Bad data from peer 96 ccode = PLDM_ERROR_INVALID_DATA; 97 break; 98 case -EOVERFLOW: 99 case -EBADMSG: 100 // Bad data from peer 101 ccode = PLDM_ERROR_INVALID_LENGTH; 102 break; 103 default: 104 // general error 105 ccode = PLDM_ERROR; 106 } 107 108 return pldm_fd_reply_cc(ccode, req_hdr, resp, resp_payload_len); 109 } 110 111 LIBPLDM_CC_NONNULL 112 static void pldm_fd_set_state(struct pldm_fd *fd, 113 enum pldm_firmware_device_states state) 114 { 115 /* pldm_fd_set_idle should be used instead */ 116 assert(state != PLDM_FD_STATE_IDLE); 117 118 if (fd->state == state) { 119 return; 120 } 121 122 fd->prev_state = fd->state; 123 fd->state = state; 124 } 125 126 LIBPLDM_CC_NONNULL 127 static void pldm_fd_set_idle(struct pldm_fd *fd, 128 enum pldm_get_status_reason_code_values reason) 129 { 130 fd->prev_state = fd->state; 131 fd->state = PLDM_FD_STATE_IDLE; 132 fd->reason = reason; 133 fd->ua_address_set = false; 134 } 135 136 LIBPLDM_CC_NONNULL 137 static void pldm_fd_idle_timeout(struct pldm_fd *fd) 138 { 139 enum pldm_get_status_reason_code_values reason = PLDM_FD_INITIALIZATION; 140 141 switch (fd->state) { 142 case PLDM_FD_STATE_IDLE: 143 return; 144 case PLDM_FD_STATE_LEARN_COMPONENTS: 145 reason = PLDM_FD_TIMEOUT_LEARN_COMPONENT; 146 break; 147 case PLDM_FD_STATE_READY_XFER: 148 reason = PLDM_FD_TIMEOUT_READY_XFER; 149 break; 150 case PLDM_FD_STATE_DOWNLOAD: 151 reason = PLDM_FD_TIMEOUT_DOWNLOAD; 152 break; 153 case PLDM_FD_STATE_VERIFY: 154 reason = PLDM_FD_TIMEOUT_VERIFY; 155 break; 156 case PLDM_FD_STATE_APPLY: 157 reason = PLDM_FD_TIMEOUT_APPLY; 158 break; 159 case PLDM_FD_STATE_ACTIVATE: 160 /* Not a timeout */ 161 reason = PLDM_FD_ACTIVATE_FW; 162 break; 163 } 164 165 pldm_fd_set_idle(fd, reason); 166 } 167 168 LIBPLDM_CC_NONNULL 169 static void pldm_fd_get_aux_state(const struct pldm_fd *fd, uint8_t *aux_state, 170 uint8_t *aux_state_status) 171 { 172 *aux_state_status = 0; 173 174 switch (fd->req.state) { 175 case PLDM_FD_REQ_UNUSED: 176 *aux_state = PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER; 177 break; 178 case PLDM_FD_REQ_SENT: 179 *aux_state = PLDM_FD_OPERATION_IN_PROGRESS; 180 break; 181 case PLDM_FD_REQ_READY: 182 if (fd->req.complete) { 183 *aux_state = PLDM_FD_OPERATION_SUCCESSFUL; 184 } else { 185 *aux_state = PLDM_FD_OPERATION_IN_PROGRESS; 186 } 187 break; 188 case PLDM_FD_REQ_FAILED: 189 *aux_state = PLDM_FD_OPERATION_FAILED; 190 *aux_state_status = fd->req.result; 191 break; 192 } 193 } 194 195 LIBPLDM_CC_NONNULL 196 static uint64_t pldm_fd_now(struct pldm_fd *fd) 197 { 198 return fd->ops->now(fd->ops_ctx); 199 } 200 201 LIBPLDM_CC_NONNULL 202 static bool pldm_fd_req_should_send(struct pldm_fd *fd) 203 { 204 pldm_fd_time_t now = pldm_fd_now(fd); 205 206 switch (fd->req.state) { 207 case PLDM_FD_REQ_UNUSED: 208 assert(false); 209 return false; 210 case PLDM_FD_REQ_READY: 211 return true; 212 case PLDM_FD_REQ_FAILED: 213 return false; 214 case PLDM_FD_REQ_SENT: 215 if (now < fd->req.sent_time) { 216 /* Time went backwards */ 217 return false; 218 } 219 220 /* Send if retry time has elapsed */ 221 return (now - fd->req.sent_time) >= fd->fd_t2_retry_time; 222 } 223 return false; 224 } 225 226 /* Allocate the next instance ID. Only one request is outstanding so cycling 227 * through the range is OK */ 228 LIBPLDM_CC_NONNULL 229 static uint8_t pldm_fd_req_next_instance(struct pldm_fd_req *req) 230 { 231 req->instance_id = (req->instance_id + 1) % INSTANCE_ID_COUNT; 232 return req->instance_id; 233 } 234 235 LIBPLDM_CC_NONNULL 236 static int pldm_fd_qdi(struct pldm_fd *fd, const struct pldm_header_info *hdr, 237 const struct pldm_msg *req LIBPLDM_CC_UNUSED, 238 size_t req_payload_len, struct pldm_msg *resp, 239 size_t *resp_payload_len) 240 { 241 uint8_t descriptor_count; 242 const struct pldm_descriptor *descriptors; 243 int rc; 244 245 /* QDI has no request data */ 246 if (req_payload_len != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) { 247 return pldm_fd_reply_cc(PLDM_ERROR_INVALID_LENGTH, hdr, resp, 248 resp_payload_len); 249 } 250 251 /* Retrieve platform-specific data */ 252 rc = fd->ops->device_identifiers(fd->ops_ctx, &descriptor_count, 253 &descriptors); 254 if (rc) { 255 return pldm_fd_reply_cc(PLDM_ERROR, hdr, resp, 256 resp_payload_len); 257 } 258 259 rc = encode_query_device_identifiers_resp(hdr->instance, 260 descriptor_count, descriptors, 261 resp, resp_payload_len); 262 263 if (rc) { 264 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 265 } 266 267 return 0; 268 } 269 270 LIBPLDM_CC_NONNULL 271 static int pldm_fd_fw_param(struct pldm_fd *fd, 272 const struct pldm_header_info *hdr, 273 const struct pldm_msg *req LIBPLDM_CC_UNUSED, 274 size_t req_payload_len, struct pldm_msg *resp, 275 size_t *resp_payload_len) 276 { 277 uint16_t entry_count; 278 const struct pldm_firmware_component_standalone **entries; 279 PLDM_MSGBUF_DEFINE_P(buf); 280 int rc; 281 282 /* No request data */ 283 if (req_payload_len != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) { 284 return pldm_fd_reply_cc(PLDM_ERROR_INVALID_LENGTH, hdr, resp, 285 resp_payload_len); 286 } 287 288 /* Retrieve platform-specific data */ 289 rc = fd->ops->components(fd->ops_ctx, &entry_count, &entries); 290 if (rc) { 291 return pldm_fd_reply_cc(PLDM_ERROR, hdr, resp, 292 resp_payload_len); 293 } 294 295 rc = pldm_msgbuf_init_errno(buf, 0, resp->payload, *resp_payload_len); 296 if (rc) { 297 return rc; 298 } 299 300 /* Add the fixed parameters */ 301 { 302 struct pldm_get_firmware_parameters_resp_full fwp = { 303 .completion_code = PLDM_SUCCESS, 304 // TODO defaulted to 0, could have a callback. 305 .capabilities_during_update = { 0 }, 306 .comp_count = entry_count, 307 }; 308 /* fill active and pending strings */ 309 rc = fd->ops->imageset_versions( 310 fd->ops_ctx, &fwp.active_comp_image_set_ver_str, 311 &fwp.pending_comp_image_set_ver_str); 312 if (rc) { 313 return pldm_msgbuf_discard( 314 buf, pldm_fd_reply_cc(PLDM_ERROR, hdr, resp, 315 resp_payload_len)); 316 } 317 318 size_t len = buf->remaining; 319 rc = encode_get_firmware_parameters_resp(hdr->instance, &fwp, 320 resp, &len); 321 if (rc) { 322 return pldm_msgbuf_discard( 323 buf, pldm_fd_reply_errno(rc, hdr, resp, 324 resp_payload_len)); 325 } 326 rc = pldm_msgbuf_skip(buf, len); 327 if (rc) { 328 return pldm_msgbuf_discard(buf, rc); 329 } 330 } 331 332 /* Add the component table entries */ 333 for (uint16_t i = 0; i < entry_count; i++) { 334 const struct pldm_firmware_component_standalone *e = entries[i]; 335 void *out = NULL; 336 size_t len; 337 338 struct pldm_component_parameter_entry_full comp = { 339 .comp_classification = e->comp_classification, 340 .comp_identifier = e->comp_identifier, 341 .comp_classification_index = 342 e->comp_classification_index, 343 344 .active_ver = e->active_ver, 345 .pending_ver = e->pending_ver, 346 347 .comp_activation_methods = e->comp_activation_methods, 348 .capabilities_during_update = 349 e->capabilities_during_update, 350 }; 351 352 if (pldm_msgbuf_peek_remaining(buf, &out, &len)) { 353 return pldm_msgbuf_discard(buf, rc); 354 } 355 356 rc = encode_get_firmware_parameters_resp_comp_entry(&comp, out, 357 &len); 358 if (rc) { 359 return pldm_msgbuf_discard( 360 buf, pldm_fd_reply_errno(rc, hdr, resp, 361 resp_payload_len)); 362 } 363 364 pldm_msgbuf_skip(buf, len); 365 } 366 367 return pldm_msgbuf_complete_used(buf, *resp_payload_len, 368 resp_payload_len); 369 } 370 371 LIBPLDM_CC_NONNULL 372 static int pldm_fd_request_update(struct pldm_fd *fd, 373 const struct pldm_header_info *hdr, 374 const struct pldm_msg *req, 375 size_t req_payload_len, struct pldm_msg *resp, 376 size_t *resp_payload_len, uint8_t address) 377 { 378 struct pldm_request_update_req_full upd; 379 const struct pldm_request_update_resp resp_data = { 380 .fd_meta_data_len = 0, 381 .fd_will_send_pkg_data = 0, 382 }; 383 int rc; 384 385 if (fd->state != PLDM_FD_STATE_IDLE) { 386 return pldm_fd_reply_cc(PLDM_FWUP_ALREADY_IN_UPDATE_MODE, hdr, 387 resp, resp_payload_len); 388 } 389 390 rc = decode_request_update_req(req, req_payload_len, &upd); 391 if (rc) { 392 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 393 } 394 395 /* No metadata nor pkg data */ 396 rc = encode_request_update_resp(hdr->instance, &resp_data, resp, 397 resp_payload_len); 398 if (rc) { 399 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 400 } 401 402 // TODO pass num_of_comp and image_set_ver to application? 403 404 fd->max_transfer = 405 fd->ops->transfer_size(fd->ops_ctx, upd.max_transfer_size); 406 if (fd->max_transfer > upd.max_transfer_size) { 407 /* Limit to UA's size */ 408 fd->max_transfer = upd.max_transfer_size; 409 } 410 if (fd->max_transfer < PLDM_FWUP_BASELINE_TRANSFER_SIZE) { 411 /* Don't let it be zero, that will loop forever */ 412 fd->max_transfer = PLDM_FWUP_BASELINE_TRANSFER_SIZE; 413 } 414 fd->ua_address = address; 415 fd->ua_address_set = true; 416 417 pldm_fd_set_state(fd, PLDM_FD_STATE_LEARN_COMPONENTS); 418 419 return 0; 420 } 421 422 /* wrapper around ops->cancel, will only run ops->cancel when a component update is 423 * active */ 424 LIBPLDM_CC_NONNULL 425 static void pldm_fd_maybe_cancel_component(struct pldm_fd *fd) 426 { 427 bool cancel = false; 428 429 switch (fd->state) { 430 case PLDM_FD_STATE_DOWNLOAD: 431 case PLDM_FD_STATE_VERIFY: 432 cancel = true; 433 break; 434 case PLDM_FD_STATE_APPLY: 435 /* In apply state, once the application ops->apply() has completed 436 * successfully the component is no longer in update state. 437 * In that case the cancel should not be forwarded to the application. 438 * This can occur if a cancel is received while waiting for the 439 * response to a success ApplyComplete. */ 440 cancel = !(fd->req.complete && 441 fd->req.result == PLDM_FWUP_APPLY_SUCCESS); 442 break; 443 default: 444 break; 445 } 446 447 if (cancel) { 448 /* Call the platform handler for the current component in progress */ 449 fd->ops->cancel_update_component(fd->ops_ctx, &fd->update_comp); 450 } 451 } 452 453 /* Wrapper around ops->update_component() that first checks that the component 454 * is in the list returned from ops->components() */ 455 LIBPLDM_CC_NONNULL 456 static enum pldm_component_response_codes pldm_fd_check_update_component( 457 struct pldm_fd *fd, bool update, 458 const struct pldm_firmware_update_component *comp) 459 { 460 bool found; 461 uint16_t entry_count; 462 int rc; 463 464 const struct pldm_firmware_component_standalone **entries; 465 rc = fd->ops->components(fd->ops_ctx, &entry_count, &entries); 466 if (rc) { 467 return PLDM_CRC_COMP_NOT_SUPPORTED; 468 } 469 470 found = false; 471 for (uint16_t i = 0; i < entry_count; i++) { 472 if (entries[i]->comp_classification == 473 comp->comp_classification && 474 entries[i]->comp_identifier == comp->comp_identifier && 475 entries[i]->comp_classification_index == 476 comp->comp_classification_index) { 477 found = true; 478 break; 479 } 480 } 481 if (found) { 482 return fd->ops->update_component(fd->ops_ctx, update, comp); 483 } 484 return PLDM_CRC_COMP_NOT_SUPPORTED; 485 } 486 487 LIBPLDM_CC_NONNULL 488 static int pldm_fd_pass_comp(struct pldm_fd *fd, 489 const struct pldm_header_info *hdr, 490 const struct pldm_msg *req, size_t req_payload_len, 491 struct pldm_msg *resp, size_t *resp_payload_len) 492 { 493 struct pldm_pass_component_table_req_full pcomp; 494 uint8_t comp_response_code; 495 int rc; 496 497 if (fd->state != PLDM_FD_STATE_LEARN_COMPONENTS) { 498 return pldm_fd_reply_cc(PLDM_FWUP_INVALID_STATE_FOR_COMMAND, 499 hdr, resp, resp_payload_len); 500 } 501 502 /* fd->update_comp is used as temporary storage during PassComponent validation */ 503 /* Some portions are unused for PassComponentTable */ 504 fd->update_comp.comp_image_size = 0; 505 fd->update_comp.update_option_flags.value = 0; 506 507 rc = decode_pass_component_table_req(req, req_payload_len, &pcomp); 508 if (rc) { 509 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 510 } 511 512 fd->update_comp.comp_classification = pcomp.comp_classification; 513 fd->update_comp.comp_identifier = pcomp.comp_identifier; 514 fd->update_comp.comp_classification_index = 515 pcomp.comp_classification_index; 516 fd->update_comp.comp_comparison_stamp = pcomp.comp_comparison_stamp; 517 memcpy(&fd->update_comp.version, &pcomp.version, sizeof(pcomp.version)); 518 519 comp_response_code = 520 pldm_fd_check_update_component(fd, false, &fd->update_comp); 521 522 const struct pldm_pass_component_table_resp resp_data = { 523 /* Component Response Code is 0 for ComponentResponse, 1 otherwise */ 524 .comp_resp = (comp_response_code != 0), 525 .comp_resp_code = comp_response_code, 526 }; 527 528 rc = encode_pass_component_table_resp(hdr->instance, &resp_data, resp, 529 resp_payload_len); 530 if (rc) { 531 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 532 } 533 534 if (pcomp.transfer_flag & PLDM_END) { 535 pldm_fd_set_state(fd, PLDM_FD_STATE_READY_XFER); 536 } 537 538 return 0; 539 } 540 541 LIBPLDM_CC_NONNULL 542 static int pldm_fd_update_comp(struct pldm_fd *fd, 543 const struct pldm_header_info *hdr, 544 const struct pldm_msg *req, 545 size_t req_payload_len, struct pldm_msg *resp, 546 size_t *resp_payload_len) 547 { 548 struct pldm_update_component_req_full up; 549 uint8_t comp_response_code; 550 int rc; 551 552 if (fd->state != PLDM_FD_STATE_READY_XFER) { 553 return pldm_fd_reply_cc(PLDM_FWUP_INVALID_STATE_FOR_COMMAND, 554 hdr, resp, resp_payload_len); 555 } 556 557 rc = decode_update_component_req(req, req_payload_len, &up); 558 if (rc) { 559 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 560 } 561 562 /* Store update_comp to pass to further callbacks. This persists 563 * until the component update completes or is cancelled */ 564 fd->update_comp.comp_classification = up.comp_classification; 565 fd->update_comp.comp_identifier = up.comp_identifier; 566 fd->update_comp.comp_classification_index = 567 up.comp_classification_index; 568 fd->update_comp.comp_comparison_stamp = up.comp_comparison_stamp; 569 fd->update_comp.comp_image_size = up.comp_image_size; 570 fd->update_comp.update_option_flags = up.update_option_flags; 571 memcpy(&fd->update_comp.version, &up.version, sizeof(up.version)); 572 573 comp_response_code = 574 pldm_fd_check_update_component(fd, true, &fd->update_comp); 575 576 // Mask to only the "Force Update" flag, others are not handled. 577 bitfield32_t update_flags = { 578 .bits.bit0 = fd->update_comp.update_option_flags.bits.bit0 579 }; 580 581 const struct pldm_update_component_resp resp_data = { 582 /* Component Response Code is 0 for ComponentResponse, 1 otherwise */ 583 .comp_compatibility_resp = (comp_response_code != 0), 584 .comp_compatibility_resp_code = comp_response_code, 585 .update_option_flags_enabled = update_flags, 586 .time_before_req_fw_data = 0, 587 }; 588 589 rc = encode_update_component_resp(hdr->instance, &resp_data, resp, 590 resp_payload_len); 591 if (rc) { 592 /* Encoding response failed */ 593 if (comp_response_code == PLDM_CRC_COMP_CAN_BE_UPDATED) { 594 /* Inform the application of cancellation. Call it directly 595 * rather than going through pldm_fd_maybe_cancel_component() */ 596 fd->ops->cancel_update_component(fd->ops_ctx, 597 &fd->update_comp); 598 } 599 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 600 } 601 602 /* Set up download state */ 603 if (comp_response_code == PLDM_CRC_COMP_CAN_BE_UPDATED) { 604 memset(&fd->specific, 0x0, sizeof(fd->specific)); 605 fd->update_flags = update_flags; 606 fd->req.state = PLDM_FD_REQ_READY; 607 fd->req.complete = false; 608 pldm_fd_set_state(fd, PLDM_FD_STATE_DOWNLOAD); 609 } 610 611 return 0; 612 } 613 614 LIBPLDM_CC_NONNULL 615 static int pldm_fd_get_status(struct pldm_fd *fd, 616 const struct pldm_header_info *hdr, 617 const struct pldm_msg *req LIBPLDM_CC_UNUSED, 618 size_t req_payload_len, struct pldm_msg *resp, 619 size_t *resp_payload_len) 620 { 621 int rc; 622 623 /* No request data */ 624 if (req_payload_len != PLDM_GET_STATUS_REQ_BYTES) { 625 return pldm_fd_reply_cc(PLDM_ERROR_INVALID_LENGTH, hdr, resp, 626 resp_payload_len); 627 } 628 629 /* Defaults */ 630 struct pldm_get_status_resp st = { 631 .current_state = fd->state, 632 .previous_state = fd->prev_state, 633 .progress_percent = PROGRESS_PERCENT_NOT_SUPPORTED, 634 }; 635 636 pldm_fd_get_aux_state(fd, &st.aux_state, &st.aux_state_status); 637 638 switch (fd->state) { 639 case PLDM_FD_STATE_IDLE: 640 st.reason_code = fd->reason; 641 break; 642 case PLDM_FD_STATE_DOWNLOAD: 643 if (fd->update_comp.comp_image_size > 0) { 644 uint32_t one_percent = 645 fd->update_comp.comp_image_size / 100; 646 if (fd->update_comp.comp_image_size % 100 != 0) { 647 one_percent += 1; 648 } 649 st.progress_percent = 650 (fd->specific.download.offset / one_percent); 651 } 652 st.update_option_flags_enabled = fd->update_flags; 653 break; 654 case PLDM_FD_STATE_VERIFY: 655 st.update_option_flags_enabled = fd->update_flags; 656 st.progress_percent = fd->specific.verify.progress_percent; 657 break; 658 case PLDM_FD_STATE_APPLY: 659 st.update_option_flags_enabled = fd->update_flags; 660 st.progress_percent = fd->specific.apply.progress_percent; 661 break; 662 default: 663 break; 664 } 665 666 rc = encode_get_status_resp(hdr->instance, &st, resp, resp_payload_len); 667 if (rc) { 668 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 669 } 670 671 return 0; 672 } 673 674 LIBPLDM_CC_NONNULL 675 static int pldm_fd_cancel_update_comp( 676 struct pldm_fd *fd, const struct pldm_header_info *hdr, 677 const struct pldm_msg *req LIBPLDM_CC_UNUSED, size_t req_payload_len, 678 struct pldm_msg *resp, size_t *resp_payload_len) 679 { 680 int rc; 681 682 /* No request data */ 683 if (req_payload_len != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) { 684 return pldm_fd_reply_cc(PLDM_ERROR_INVALID_LENGTH, hdr, resp, 685 resp_payload_len); 686 } 687 688 switch (fd->state) { 689 case PLDM_FD_STATE_DOWNLOAD: 690 case PLDM_FD_STATE_VERIFY: 691 case PLDM_FD_STATE_APPLY: 692 break; 693 default: 694 return pldm_fd_reply_cc(PLDM_FWUP_NOT_IN_UPDATE_MODE, hdr, resp, 695 resp_payload_len); 696 } 697 698 /* No response payload */ 699 rc = pldm_fd_reply_cc(PLDM_SUCCESS, hdr, resp, resp_payload_len); 700 if (rc) { 701 return rc; 702 } 703 704 pldm_fd_maybe_cancel_component(fd); 705 pldm_fd_set_state(fd, PLDM_FD_STATE_READY_XFER); 706 707 return 0; 708 } 709 710 LIBPLDM_CC_NONNULL 711 static int pldm_fd_cancel_update(struct pldm_fd *fd, 712 const struct pldm_header_info *hdr, 713 const struct pldm_msg *req LIBPLDM_CC_UNUSED, 714 size_t req_payload_len, struct pldm_msg *resp, 715 size_t *resp_payload_len) 716 { 717 int rc; 718 719 /* No request data */ 720 if (req_payload_len != PLDM_CANCEL_UPDATE_REQ_BYTES) { 721 return pldm_fd_reply_cc(PLDM_ERROR_INVALID_LENGTH, hdr, resp, 722 resp_payload_len); 723 } 724 725 if (fd->state == PLDM_FD_STATE_IDLE) { 726 return pldm_fd_reply_cc(PLDM_FWUP_NOT_IN_UPDATE_MODE, hdr, resp, 727 resp_payload_len); 728 } 729 730 /* Assume non_functioning_component_indication = False, in future 731 * could add a platform callback */ 732 const struct pldm_cancel_update_resp resp_data = { 733 .non_functioning_component_indication = 0, 734 .non_functioning_component_bitmap = 0, 735 }; 736 rc = encode_cancel_update_resp(hdr->instance, &resp_data, resp, 737 resp_payload_len); 738 if (rc) { 739 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 740 } 741 742 pldm_fd_maybe_cancel_component(fd); 743 pldm_fd_set_idle(fd, PLDM_FD_CANCEL_UPDATE); 744 745 return 0; 746 } 747 748 LIBPLDM_CC_NONNULL 749 static int pldm_fd_activate_firmware(struct pldm_fd *fd, 750 const struct pldm_header_info *hdr, 751 const struct pldm_msg *req, 752 size_t req_payload_len, 753 struct pldm_msg *resp, 754 size_t *resp_payload_len) 755 { 756 uint16_t estimated_time; 757 uint8_t ccode; 758 int rc; 759 bool self_contained; 760 761 rc = decode_activate_firmware_req(req, req_payload_len, 762 &self_contained); 763 if (rc) { 764 return pldm_fd_reply_errno(rc, hdr, resp, resp_payload_len); 765 } 766 767 if (fd->state != PLDM_FD_STATE_READY_XFER) { 768 return pldm_fd_reply_cc(PLDM_FWUP_INVALID_STATE_FOR_COMMAND, 769 hdr, resp, resp_payload_len); 770 } 771 772 estimated_time = 0; 773 ccode = fd->ops->activate(fd->ops_ctx, self_contained, &estimated_time); 774 775 if (ccode == PLDM_SUCCESS || 776 ccode == PLDM_FWUP_ACTIVATION_NOT_REQUIRED) { 777 /* Transition through states so that the prev_state is correct */ 778 pldm_fd_set_state(fd, PLDM_FD_STATE_ACTIVATE); 779 pldm_fd_set_idle(fd, PLDM_FD_ACTIVATE_FW); 780 } 781 782 if (ccode == PLDM_SUCCESS) { 783 const struct pldm_activate_firmware_resp resp_data = { 784 .estimated_time_activation = estimated_time, 785 }; 786 rc = encode_activate_firmware_resp(hdr->instance, &resp_data, 787 resp, resp_payload_len); 788 if (rc) { 789 return pldm_fd_reply_errno(rc, hdr, resp, 790 resp_payload_len); 791 } 792 } else { 793 return pldm_fd_reply_cc(ccode, hdr, resp, resp_payload_len); 794 } 795 796 return 0; 797 } 798 799 LIBPLDM_CC_NONNULL 800 static uint32_t pldm_fd_fwdata_size(struct pldm_fd *fd) 801 { 802 uint32_t size; 803 804 if (fd->state != PLDM_FD_STATE_DOWNLOAD) { 805 assert(false); 806 return 0; 807 } 808 809 if (fd->specific.download.offset > fd->update_comp.comp_image_size) { 810 assert(false); 811 return 0; 812 } 813 size = fd->update_comp.comp_image_size - fd->specific.download.offset; 814 815 if (size > fd->max_transfer) { 816 size = fd->max_transfer; 817 } 818 return size; 819 } 820 821 LIBPLDM_CC_NONNULL 822 static int pldm_fd_handle_fwdata_resp(struct pldm_fd *fd, 823 const struct pldm_msg *resp, 824 size_t resp_payload_len) 825 { 826 struct pldm_fd_download *dl; 827 uint32_t fwdata_size; 828 uint8_t res; 829 830 if (fd->state != PLDM_FD_STATE_DOWNLOAD) { 831 return -EPROTO; 832 } 833 834 if (fd->req.state != PLDM_FD_REQ_SENT) { 835 /* Not waiting for a response, ignore it */ 836 return -EPROTO; 837 } 838 839 dl = &fd->specific.download; 840 if (fd->req.complete) { 841 /* Received data after completion */ 842 return -EPROTO; 843 } 844 845 switch (resp->payload[0]) { 846 case PLDM_SUCCESS: 847 break; 848 case PLDM_FWUP_RETRY_REQUEST_FW_DATA: 849 /* Just return, let the retry timer send another request later */ 850 return 0; 851 default: 852 /* Send a TransferComplete failure */ 853 fd->req.state = PLDM_FD_REQ_READY; 854 fd->req.complete = true; 855 fd->req.result = PLDM_FWUP_FD_ABORTED_TRANSFER; 856 return 0; 857 } 858 859 /* Handle the received data */ 860 861 fwdata_size = pldm_fd_fwdata_size(fd); 862 if (resp_payload_len != fwdata_size + 1) { 863 /* Data is incorrect size. Could indicate MCTP corruption, drop it 864 * and let retry timer handle it */ 865 return -EOVERFLOW; 866 } 867 868 /* Check pldm_fd_fwdata_size calculation, should not fail */ 869 if (dl->offset + fwdata_size < dl->offset || 870 dl->offset + fwdata_size > fd->update_comp.comp_image_size) { 871 assert(false); 872 return -EINVAL; 873 } 874 875 /* Provide the data chunk to the device */ 876 res = fd->ops->firmware_data(fd->ops_ctx, dl->offset, &resp->payload[1], 877 fwdata_size, &fd->update_comp); 878 879 fd->req.state = PLDM_FD_REQ_READY; 880 if (res == PLDM_FWUP_TRANSFER_SUCCESS) { 881 /* Move to next offset */ 882 dl->offset += fwdata_size; 883 if (dl->offset == fd->update_comp.comp_image_size) { 884 /* Mark as complete, next progress() call will send the TransferComplete request */ 885 fd->req.complete = true; 886 fd->req.result = PLDM_FWUP_TRANSFER_SUCCESS; 887 } 888 } else { 889 /* Pass the callback error as the TransferResult */ 890 fd->req.complete = true; 891 fd->req.result = res; 892 } 893 894 return 0; 895 } 896 897 LIBPLDM_CC_NONNULL 898 static int pldm_fd_handle_transfer_complete_resp( 899 struct pldm_fd *fd, const struct pldm_msg *resp LIBPLDM_CC_UNUSED, 900 size_t resp_payload_len LIBPLDM_CC_UNUSED) 901 { 902 if (fd->state != PLDM_FD_STATE_DOWNLOAD) { 903 return -EPROTO; 904 } 905 906 if (fd->req.state != PLDM_FD_REQ_SENT) { 907 /* Not waiting for a response, ignore it */ 908 return -EPROTO; 909 } 910 911 if (!fd->req.complete) { 912 /* Were waiting for RequestFirmwareData instead, ignore it */ 913 return -EPROTO; 914 } 915 916 /* Disregard the response completion code */ 917 918 /* Next state depends whether the transfer succeeded */ 919 if (fd->req.result == PLDM_FWUP_TRANSFER_SUCCESS) { 920 /* Switch to Verify */ 921 memset(&fd->specific, 0x0, sizeof(fd->specific)); 922 fd->specific.verify.progress_percent = 923 PROGRESS_PERCENT_NOT_SUPPORTED; 924 fd->req.state = PLDM_FD_REQ_READY; 925 fd->req.complete = false; 926 pldm_fd_set_state(fd, PLDM_FD_STATE_VERIFY); 927 } else { 928 /* Wait for UA to cancel */ 929 fd->req.state = PLDM_FD_REQ_FAILED; 930 } 931 return 0; 932 } 933 934 LIBPLDM_CC_NONNULL 935 static int pldm_fd_handle_verify_complete_resp( 936 struct pldm_fd *fd, const struct pldm_msg *resp LIBPLDM_CC_UNUSED, 937 size_t resp_payload_len LIBPLDM_CC_UNUSED) 938 { 939 if (fd->state != PLDM_FD_STATE_VERIFY) { 940 return -EPROTO; 941 } 942 943 if (fd->req.state != PLDM_FD_REQ_SENT) { 944 /* Not waiting for a response, ignore it */ 945 return -EPROTO; 946 } 947 948 assert(fd->req.complete); 949 950 /* Disregard the response completion code */ 951 952 /* Next state depends whether the verify succeeded */ 953 if (fd->req.result == PLDM_FWUP_VERIFY_SUCCESS) { 954 /* Switch to Apply */ 955 memset(&fd->specific, 0x0, sizeof(fd->specific)); 956 fd->specific.apply.progress_percent = 957 PROGRESS_PERCENT_NOT_SUPPORTED; 958 fd->req.state = PLDM_FD_REQ_READY; 959 fd->req.complete = false; 960 pldm_fd_set_state(fd, PLDM_FD_STATE_APPLY); 961 } else { 962 /* Wait for UA to cancel */ 963 fd->req.state = PLDM_FD_REQ_FAILED; 964 } 965 return 0; 966 } 967 968 LIBPLDM_CC_NONNULL 969 static int pldm_fd_handle_apply_complete_resp( 970 struct pldm_fd *fd, const struct pldm_msg *resp LIBPLDM_CC_UNUSED, 971 size_t resp_payload_len LIBPLDM_CC_UNUSED) 972 { 973 if (fd->state != PLDM_FD_STATE_APPLY) { 974 return -EPROTO; 975 } 976 977 if (fd->req.state != PLDM_FD_REQ_SENT) { 978 /* Not waiting for a response, ignore it */ 979 return -EPROTO; 980 } 981 982 assert(fd->req.complete); 983 984 /* Disregard the response completion code */ 985 986 /* Next state depends whether the apply succeeded */ 987 if (fd->req.result == PLDM_FWUP_APPLY_SUCCESS) { 988 /* Switch to ReadyXfer */ 989 fd->req.state = PLDM_FD_REQ_UNUSED; 990 pldm_fd_set_state(fd, PLDM_FD_STATE_READY_XFER); 991 } else { 992 /* Wait for UA to cancel */ 993 fd->req.state = PLDM_FD_REQ_FAILED; 994 } 995 return 0; 996 } 997 998 LIBPLDM_CC_NONNULL 999 static int pldm_fd_handle_resp(struct pldm_fd *fd, pldm_tid_t address, 1000 const void *resp_msg, size_t resp_len) 1001 { 1002 size_t resp_payload_len; 1003 const struct pldm_msg *resp = resp_msg; 1004 1005 if (!(fd->ua_address_set && fd->ua_address == address)) { 1006 // Either an early response, or a response from a wrong TID */ 1007 return -EBUSY; 1008 } 1009 1010 /* Must have a ccode */ 1011 if (resp_len < sizeof(struct pldm_msg_hdr) + 1) { 1012 return -EINVAL; 1013 } 1014 resp_payload_len = resp_len - sizeof(struct pldm_msg_hdr); 1015 1016 if (fd->req.state != PLDM_FD_REQ_SENT) { 1017 // No response was expected 1018 return -EPROTO; 1019 } 1020 1021 if (fd->req.instance_id != resp->hdr.instance_id) { 1022 // Response wasn't for the expected request 1023 return -EPROTO; 1024 } 1025 if (fd->req.command != resp->hdr.command) { 1026 // Response wasn't for the expected request 1027 return -EPROTO; 1028 } 1029 1030 fd->update_timestamp_fd_t1 = pldm_fd_now(fd); 1031 1032 switch (resp->hdr.command) { 1033 case PLDM_REQUEST_FIRMWARE_DATA: 1034 return pldm_fd_handle_fwdata_resp(fd, resp, resp_payload_len); 1035 break; 1036 case PLDM_TRANSFER_COMPLETE: 1037 return pldm_fd_handle_transfer_complete_resp(fd, resp, 1038 resp_payload_len); 1039 break; 1040 case PLDM_VERIFY_COMPLETE: 1041 return pldm_fd_handle_verify_complete_resp(fd, resp, 1042 resp_payload_len); 1043 break; 1044 case PLDM_APPLY_COMPLETE: 1045 return pldm_fd_handle_apply_complete_resp(fd, resp, 1046 resp_payload_len); 1047 break; 1048 default: 1049 /* Unsolicited response. Already compared to command above */ 1050 assert(false); 1051 return -EINVAL; 1052 } 1053 } 1054 1055 LIBPLDM_CC_NONNULL 1056 static int pldm_fd_progress_download(struct pldm_fd *fd, struct pldm_msg *req, 1057 size_t *req_payload_len) 1058 { 1059 uint8_t instance_id; 1060 struct pldm_fd_download *dl; 1061 int rc; 1062 1063 if (!pldm_fd_req_should_send(fd)) { 1064 /* Nothing to do */ 1065 *req_payload_len = 0; 1066 return 0; 1067 } 1068 1069 instance_id = pldm_fd_req_next_instance(&fd->req); 1070 dl = &fd->specific.download; 1071 if (fd->req.complete) { 1072 /* Send TransferComplete */ 1073 rc = encode_transfer_complete_req(instance_id, fd->req.result, 1074 req, req_payload_len); 1075 } else { 1076 /* Send a new RequestFirmwareData */ 1077 const struct pldm_request_firmware_data_req req_params = { 1078 .offset = dl->offset, 1079 .length = pldm_fd_fwdata_size(fd), 1080 }; 1081 1082 rc = encode_request_firmware_data_req(instance_id, &req_params, 1083 req, req_payload_len); 1084 } 1085 1086 if (rc) { 1087 return rc; 1088 } 1089 1090 /* Wait for response */ 1091 fd->req.state = PLDM_FD_REQ_SENT; 1092 fd->req.instance_id = req->hdr.instance_id; 1093 fd->req.command = req->hdr.command; 1094 fd->req.sent_time = pldm_fd_now(fd); 1095 1096 return 0; 1097 } 1098 1099 LIBPLDM_CC_NONNULL 1100 static int pldm_fd_progress_verify(struct pldm_fd *fd, struct pldm_msg *req, 1101 size_t *req_payload_len) 1102 { 1103 uint8_t instance_id; 1104 int rc; 1105 1106 if (!pldm_fd_req_should_send(fd)) { 1107 /* Nothing to do */ 1108 *req_payload_len = 0; 1109 return 0; 1110 } 1111 1112 if (!fd->req.complete) { 1113 bool pending = false; 1114 uint8_t res; 1115 res = fd->ops->verify(fd->ops_ctx, &fd->update_comp, &pending, 1116 &fd->specific.verify.progress_percent); 1117 if (pending) { 1118 if (res == PLDM_FWUP_VERIFY_SUCCESS) { 1119 /* Return without a VerifyComplete request. 1120 * Will call verify() again on next call */ 1121 *req_payload_len = 0; 1122 return 0; 1123 } 1124 /* This is an API infraction by the implementer, return a distinctive failure */ 1125 res = PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MAX; 1126 } 1127 fd->req.result = res; 1128 fd->req.complete = true; 1129 } 1130 1131 instance_id = pldm_fd_req_next_instance(&fd->req); 1132 rc = encode_verify_complete_req(instance_id, fd->req.result, req, 1133 req_payload_len); 1134 if (rc) { 1135 return rc; 1136 } 1137 1138 /* Wait for response */ 1139 fd->req.state = PLDM_FD_REQ_SENT; 1140 fd->req.instance_id = req->hdr.instance_id; 1141 fd->req.command = req->hdr.command; 1142 fd->req.sent_time = pldm_fd_now(fd); 1143 1144 return 0; 1145 } 1146 1147 LIBPLDM_CC_NONNULL 1148 static int pldm_fd_progress_apply(struct pldm_fd *fd, struct pldm_msg *req, 1149 size_t *req_payload_len) 1150 { 1151 uint8_t instance_id; 1152 int rc; 1153 1154 if (!pldm_fd_req_should_send(fd)) { 1155 /* Nothing to do */ 1156 *req_payload_len = 0; 1157 return 0; 1158 } 1159 1160 if (!fd->req.complete) { 1161 bool pending = false; 1162 uint8_t res; 1163 res = fd->ops->apply(fd->ops_ctx, &fd->update_comp, &pending, 1164 &fd->specific.apply.progress_percent); 1165 if (pending) { 1166 if (res == PLDM_FWUP_APPLY_SUCCESS) { 1167 /* Return without a ApplyComplete request. 1168 * Will call apply() again on next call */ 1169 *req_payload_len = 0; 1170 return 0; 1171 } 1172 /* This is an API infraction by the implementer, return a distinctive failure */ 1173 res = PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MAX; 1174 } 1175 fd->req.result = res; 1176 fd->req.complete = true; 1177 if (fd->req.result == 1178 PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) { 1179 /* modified activation method isn't currently handled */ 1180 fd->req.result = PLDM_FWUP_APPLY_SUCCESS; 1181 } 1182 } 1183 1184 instance_id = pldm_fd_req_next_instance(&fd->req); 1185 const struct pldm_apply_complete_req req_data = { 1186 .apply_result = fd->req.result, 1187 .comp_activation_methods_modification = { 0 }, 1188 }; 1189 rc = encode_apply_complete_req(instance_id, &req_data, req, 1190 req_payload_len); 1191 if (rc) { 1192 return rc; 1193 } 1194 1195 /* Wait for response */ 1196 fd->req.state = PLDM_FD_REQ_SENT; 1197 fd->req.instance_id = req->hdr.instance_id; 1198 fd->req.command = req->hdr.command; 1199 fd->req.sent_time = pldm_fd_now(fd); 1200 1201 return 0; 1202 } 1203 1204 LIBPLDM_ABI_TESTING 1205 struct pldm_fd *pldm_fd_new(const struct pldm_fd_ops *ops, void *ops_ctx, 1206 struct pldm_control *control) 1207 { 1208 struct pldm_fd *fd = malloc(sizeof(*fd)); 1209 if (fd) { 1210 if (pldm_fd_setup(fd, sizeof(*fd), ops, ops_ctx, control) == 1211 0) { 1212 return fd; 1213 } 1214 free(fd); 1215 fd = NULL; 1216 } 1217 return fd; 1218 } 1219 1220 LIBPLDM_ABI_TESTING 1221 int pldm_fd_setup(struct pldm_fd *fd, size_t pldm_fd_size, 1222 const struct pldm_fd_ops *ops, void *ops_ctx, 1223 struct pldm_control *control) 1224 { 1225 int rc; 1226 1227 if (fd == NULL || ops == NULL) { 1228 return -EINVAL; 1229 } 1230 1231 if (ops->device_identifiers == NULL || ops->components == NULL || 1232 ops->imageset_versions == NULL || ops->update_component == NULL || 1233 ops->transfer_size == NULL || ops->firmware_data == NULL || 1234 ops->verify == NULL || ops->activate == NULL || 1235 ops->cancel_update_component == NULL || ops->now == NULL) { 1236 return -EINVAL; 1237 } 1238 1239 if (pldm_fd_size < sizeof(struct pldm_fd)) { 1240 /* Safety check that sufficient storage was provided for *fd, 1241 * in case PLDM_SIZEOF_PLDM_FD is incorrect */ 1242 return -EINVAL; 1243 } 1244 memset(fd, 0x0, sizeof(*fd)); 1245 fd->ops = ops; 1246 fd->ops_ctx = ops_ctx; 1247 fd->fd_t1_timeout = DEFAULT_FD_T1_TIMEOUT; 1248 fd->fd_t2_retry_time = DEFAULT_FD_T2_RETRY_TIME; 1249 1250 if (control) { 1251 rc = pldm_control_add_type(control, PLDM_FWUP, 1252 &PLDM_FD_VERSIONS, 1253 PLDM_FD_VERSIONS_COUNT, 1254 PLDM_FD_COMMANDS); 1255 if (rc) { 1256 return rc; 1257 } 1258 } 1259 1260 return 0; 1261 } 1262 1263 LIBPLDM_ABI_TESTING 1264 int pldm_fd_handle_msg(struct pldm_fd *fd, pldm_tid_t remote_address, 1265 const void *in_msg, size_t in_len, void *out_msg, 1266 size_t *out_len) 1267 { 1268 size_t req_payload_len; 1269 size_t resp_payload_len; 1270 struct pldm_header_info hdr; 1271 const struct pldm_msg *req = in_msg; 1272 struct pldm_msg *resp = out_msg; 1273 uint8_t rc; 1274 1275 if (fd == NULL || in_msg == NULL || out_msg == NULL || 1276 out_len == NULL) { 1277 return -EINVAL; 1278 } 1279 1280 if (in_len < sizeof(struct pldm_msg_hdr)) { 1281 return -EOVERFLOW; 1282 } 1283 req_payload_len = in_len - sizeof(struct pldm_msg_hdr); 1284 1285 rc = unpack_pldm_header(&req->hdr, &hdr); 1286 if (rc != PLDM_SUCCESS) { 1287 return -EINVAL; 1288 } 1289 1290 if (hdr.pldm_type != PLDM_FWUP) { 1291 /* Caller should not have passed non-pldmfw */ 1292 return -ENOMSG; 1293 } 1294 1295 if (hdr.msg_type == PLDM_RESPONSE) { 1296 *out_len = 0; 1297 return pldm_fd_handle_resp(fd, remote_address, in_msg, in_len); 1298 } 1299 1300 if (hdr.msg_type != PLDM_REQUEST) { 1301 return -EPROTO; 1302 } 1303 1304 /* Space for header plus completion code */ 1305 if (*out_len < sizeof(struct pldm_msg_hdr) + 1) { 1306 return -EOVERFLOW; 1307 } 1308 resp_payload_len = *out_len - sizeof(struct pldm_msg_hdr); 1309 1310 /* Check address */ 1311 switch (hdr.command) { 1312 /* Information or cancel commands are always allowed */ 1313 case PLDM_QUERY_DEVICE_IDENTIFIERS: 1314 case PLDM_GET_FIRMWARE_PARAMETERS: 1315 case PLDM_GET_STATUS: 1316 case PLDM_CANCEL_UPDATE: 1317 case PLDM_QUERY_DOWNSTREAM_DEVICES: 1318 case PLDM_QUERY_DOWNSTREAM_IDENTIFIERS: 1319 case PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS: 1320 /* Request Update handler will set address */ 1321 case PLDM_REQUEST_UPDATE: 1322 break; 1323 default: 1324 /* Requests must come from the same address that requested the update */ 1325 if (!fd->ua_address_set || remote_address != fd->ua_address) { 1326 return pldm_fd_reply_cc(PLDM_ERROR_NOT_READY, &hdr, 1327 resp, &resp_payload_len); 1328 } 1329 } 1330 1331 /* Update timeout */ 1332 switch (hdr.command) { 1333 case PLDM_REQUEST_UPDATE: 1334 case PLDM_PASS_COMPONENT_TABLE: 1335 case PLDM_UPDATE_COMPONENT: 1336 case PLDM_CANCEL_UPDATE: 1337 fd->update_timestamp_fd_t1 = pldm_fd_now(fd); 1338 break; 1339 default: 1340 break; 1341 } 1342 1343 /* Dispatch command. 1344 Update PLDM_FD_COMMANDS if adding new handlers */ 1345 switch (hdr.command) { 1346 case PLDM_QUERY_DEVICE_IDENTIFIERS: 1347 rc = pldm_fd_qdi(fd, &hdr, req, req_payload_len, resp, 1348 &resp_payload_len); 1349 break; 1350 case PLDM_GET_FIRMWARE_PARAMETERS: 1351 rc = pldm_fd_fw_param(fd, &hdr, req, req_payload_len, resp, 1352 &resp_payload_len); 1353 break; 1354 case PLDM_REQUEST_UPDATE: 1355 rc = pldm_fd_request_update(fd, &hdr, req, req_payload_len, 1356 resp, &resp_payload_len, 1357 remote_address); 1358 break; 1359 case PLDM_PASS_COMPONENT_TABLE: 1360 rc = pldm_fd_pass_comp(fd, &hdr, req, req_payload_len, resp, 1361 &resp_payload_len); 1362 break; 1363 case PLDM_UPDATE_COMPONENT: 1364 rc = pldm_fd_update_comp(fd, &hdr, req, req_payload_len, resp, 1365 &resp_payload_len); 1366 break; 1367 case PLDM_GET_STATUS: 1368 rc = pldm_fd_get_status(fd, &hdr, req, req_payload_len, resp, 1369 &resp_payload_len); 1370 break; 1371 case PLDM_CANCEL_UPDATE_COMPONENT: 1372 rc = pldm_fd_cancel_update_comp(fd, &hdr, req, req_payload_len, 1373 resp, &resp_payload_len); 1374 break; 1375 case PLDM_CANCEL_UPDATE: 1376 rc = pldm_fd_cancel_update(fd, &hdr, req, req_payload_len, resp, 1377 &resp_payload_len); 1378 break; 1379 case PLDM_ACTIVATE_FIRMWARE: 1380 rc = pldm_fd_activate_firmware(fd, &hdr, req, req_payload_len, 1381 resp, &resp_payload_len); 1382 break; 1383 default: 1384 rc = pldm_fd_reply_cc(PLDM_ERROR_UNSUPPORTED_PLDM_CMD, &hdr, 1385 resp, &resp_payload_len); 1386 } 1387 1388 if (rc == 0) { 1389 *out_len = resp_payload_len + sizeof(struct pldm_msg_hdr); 1390 } 1391 1392 return rc; 1393 } 1394 1395 LIBPLDM_ABI_TESTING 1396 int pldm_fd_progress(struct pldm_fd *fd, void *out_msg, size_t *out_len, 1397 pldm_tid_t *address) 1398 { 1399 size_t req_payload_len; 1400 struct pldm_msg *req = out_msg; 1401 int rc = -EINVAL; 1402 bool ua_timeout_check = false; 1403 1404 if (fd == NULL || out_msg == NULL || out_len == NULL) { 1405 return -EINVAL; 1406 } 1407 1408 /* Space for header */ 1409 if (*out_len < sizeof(struct pldm_msg_hdr)) { 1410 return -EOVERFLOW; 1411 } 1412 req_payload_len = *out_len - sizeof(struct pldm_msg_hdr); 1413 *out_len = 0; 1414 1415 // Handle FD-driven states 1416 switch (fd->state) { 1417 case PLDM_FD_STATE_DOWNLOAD: 1418 rc = pldm_fd_progress_download(fd, req, &req_payload_len); 1419 break; 1420 case PLDM_FD_STATE_VERIFY: 1421 rc = pldm_fd_progress_verify(fd, req, &req_payload_len); 1422 break; 1423 case PLDM_FD_STATE_APPLY: 1424 rc = pldm_fd_progress_apply(fd, req, &req_payload_len); 1425 break; 1426 default: 1427 req_payload_len = 0; 1428 break; 1429 } 1430 1431 // Cancel update if expected UA message isn't received within timeout 1432 switch (fd->state) { 1433 case PLDM_FD_STATE_DOWNLOAD: 1434 case PLDM_FD_STATE_VERIFY: 1435 case PLDM_FD_STATE_APPLY: 1436 // FD-driven states will time out if a response isn't received 1437 ua_timeout_check = (fd->req.state == PLDM_FD_REQ_SENT); 1438 break; 1439 case PLDM_FD_STATE_IDLE: 1440 ua_timeout_check = false; 1441 break; 1442 default: 1443 // Other Update Mode states have a timeout for the UA to 1444 // send a request 1445 ua_timeout_check = true; 1446 } 1447 1448 if (ua_timeout_check) { 1449 if ((pldm_fd_now(fd) - fd->update_timestamp_fd_t1) > 1450 fd->fd_t1_timeout) { 1451 pldm_fd_maybe_cancel_component(fd); 1452 pldm_fd_idle_timeout(fd); 1453 req_payload_len = 0; 1454 } 1455 } 1456 1457 if (rc == 0 && fd->ua_address_set && req_payload_len > 0) { 1458 *out_len = req_payload_len + sizeof(struct pldm_msg_hdr); 1459 *address = fd->ua_address; 1460 } 1461 1462 return rc; 1463 } 1464 1465 LIBPLDM_ABI_TESTING 1466 int pldm_fd_set_update_idle_timeout(struct pldm_fd *fd, uint32_t time) 1467 { 1468 if (fd == NULL) { 1469 return -EINVAL; 1470 } 1471 1472 fd->fd_t1_timeout = time; 1473 return 0; 1474 } 1475 1476 LIBPLDM_ABI_TESTING 1477 int pldm_fd_set_request_retry_time(struct pldm_fd *fd, uint32_t time) 1478 { 1479 if (fd == NULL) { 1480 return -EINVAL; 1481 } 1482 1483 fd->fd_t2_retry_time = time; 1484 return 0; 1485 } 1486