1 #include "device_updater.hpp"
2
3 #include "activation.hpp"
4 #include "update_manager.hpp"
5
6 #include <libpldm/firmware_update.h>
7
8 #include <phosphor-logging/lg2.hpp>
9
10 #include <functional>
11
12 PHOSPHOR_LOG2_USING;
13
14 namespace pldm
15 {
16
17 namespace fw_update
18 {
19
startFwUpdateFlow()20 void DeviceUpdater::startFwUpdateFlow()
21 {
22 auto instanceId = updateManager->instanceIdDb.next(eid);
23 // NumberOfComponents
24 const auto& applicableComponents =
25 std::get<ApplicableComponents>(fwDeviceIDRecord);
26 // PackageDataLength
27 const auto& fwDevicePkgData =
28 std::get<FirmwareDevicePackageData>(fwDeviceIDRecord);
29 // ComponentImageSetVersionString
30 const auto& compImageSetVersion =
31 std::get<ComponentImageSetVersion>(fwDeviceIDRecord);
32 variable_field compImgSetVerStrInfo{};
33 compImgSetVerStrInfo.ptr =
34 reinterpret_cast<const uint8_t*>(compImageSetVersion.data());
35 compImgSetVerStrInfo.length =
36 static_cast<uint8_t>(compImageSetVersion.size());
37
38 Request request(
39 sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
40 compImgSetVerStrInfo.length);
41 auto requestMsg = new (request.data()) pldm_msg;
42
43 auto rc = encode_request_update_req(
44 instanceId, maxTransferSize, applicableComponents.size(),
45 PLDM_FWUP_MIN_OUTSTANDING_REQ, fwDevicePkgData.size(),
46 PLDM_STR_TYPE_ASCII, compImgSetVerStrInfo.length, &compImgSetVerStrInfo,
47 requestMsg,
48 sizeof(struct pldm_request_update_req) + compImgSetVerStrInfo.length);
49 if (rc)
50 {
51 // Handle error scenario
52 updateManager->instanceIdDb.free(eid, instanceId);
53 error(
54 "Failed to encode request update request for endpoint ID '{EID}', response code '{RC}'",
55 "EID", eid, "RC", rc);
56 }
57
58 rc = updateManager->handler.registerRequest(
59 eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request),
60 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
61 this->requestUpdate(eid, response, respMsgLen);
62 });
63 if (rc)
64 {
65 // Handle error scenario
66 error(
67 "Failed to send request update for endpoint ID '{EID}', response code '{RC}'",
68 "EID", eid, "RC", rc);
69 }
70 }
71
requestUpdate(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)72 void DeviceUpdater::requestUpdate(mctp_eid_t eid, const pldm_msg* response,
73 size_t respMsgLen)
74 {
75 if (response == nullptr || !respMsgLen)
76 {
77 // Handle error scenario
78 error("No response received for request update for endpoint ID '{EID}'",
79 "EID", eid);
80 updateManager->updateDeviceCompletion(eid, false);
81 return;
82 }
83
84 uint8_t completionCode = 0;
85 uint16_t fdMetaDataLen = 0;
86 uint8_t fdWillSendPkgData = 0;
87
88 auto rc = decode_request_update_resp(response, respMsgLen, &completionCode,
89 &fdMetaDataLen, &fdWillSendPkgData);
90 if (rc)
91 {
92 error(
93 "Failed to decode request update response for endpoint ID '{EID}', response code '{RC}'",
94 "EID", eid, "RC", rc);
95 return;
96 }
97 if (completionCode)
98 {
99 error(
100 "Failure in request update response for endpoint ID '{EID}', completion code '{CC}'",
101 "EID", eid, "CC", completionCode);
102 updateManager->updateDeviceCompletion(eid, false);
103 return;
104 }
105
106 // Optional fields DeviceMetaData and GetPackageData not handled
107 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
108 updateManager->event,
109 std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
110 componentIndex));
111 }
112
sendPassCompTableRequest(size_t offset)113 void DeviceUpdater::sendPassCompTableRequest(size_t offset)
114 {
115 pldmRequest.reset();
116
117 auto instanceId = updateManager->instanceIdDb.next(eid);
118 // TransferFlag
119 const auto& applicableComponents =
120 std::get<ApplicableComponents>(fwDeviceIDRecord);
121 uint8_t transferFlag = 0;
122 if (applicableComponents.size() == 1)
123 {
124 transferFlag = PLDM_START_AND_END;
125 }
126 else if (offset == 0)
127 {
128 transferFlag = PLDM_START;
129 }
130 else if (offset == applicableComponents.size() - 1)
131 {
132 transferFlag = PLDM_END;
133 }
134 else
135 {
136 transferFlag = PLDM_MIDDLE;
137 }
138 const auto& comp = compImageInfos[applicableComponents[offset]];
139 // ComponentClassification
140 CompClassification compClassification = std::get<static_cast<size_t>(
141 ComponentImageInfoPos::CompClassificationPos)>(comp);
142 // ComponentIdentifier
143 CompIdentifier compIdentifier =
144 std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
145 comp);
146 // ComponentClassificationIndex
147 CompClassificationIndex compClassificationIndex{};
148 auto compKey = std::make_pair(compClassification, compIdentifier);
149 if (compInfo.contains(compKey))
150 {
151 auto search = compInfo.find(compKey);
152 compClassificationIndex = search->second;
153 }
154 else
155 {
156 // Handle error scenario
157 error(
158 "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
159 "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
160 }
161 // ComponentComparisonStamp
162 CompComparisonStamp compComparisonStamp = std::get<static_cast<size_t>(
163 ComponentImageInfoPos::CompComparisonStampPos)>(comp);
164 // ComponentVersionString
165 const auto& compVersion =
166 std::get<static_cast<size_t>(ComponentImageInfoPos::CompVersionPos)>(
167 comp);
168 variable_field compVerStrInfo{};
169 compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
170 compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
171
172 Request request(
173 sizeof(pldm_msg_hdr) + sizeof(struct pldm_pass_component_table_req) +
174 compVerStrInfo.length);
175 auto requestMsg = new (request.data()) pldm_msg;
176 auto rc = encode_pass_component_table_req(
177 instanceId, transferFlag, compClassification, compIdentifier,
178 compClassificationIndex, compComparisonStamp, PLDM_STR_TYPE_ASCII,
179 compVerStrInfo.length, &compVerStrInfo, requestMsg,
180 sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
181 if (rc)
182 {
183 // Handle error scenario
184 updateManager->instanceIdDb.free(eid, instanceId);
185 error(
186 "Failed to encode pass component table req for endpoint ID '{EID}', response code '{RC}'",
187 "EID", eid, "RC", rc);
188 }
189
190 rc = updateManager->handler.registerRequest(
191 eid, instanceId, PLDM_FWUP, PLDM_PASS_COMPONENT_TABLE,
192 std::move(request),
193 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
194 this->passCompTable(eid, response, respMsgLen);
195 });
196 if (rc)
197 {
198 // Handle error scenario
199 error(
200 "Failed to send pass component table request for endpoint ID '{EID}', response code '{RC}'",
201 "EID", eid, "RC", rc);
202 }
203 }
204
passCompTable(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)205 void DeviceUpdater::passCompTable(mctp_eid_t eid, const pldm_msg* response,
206 size_t respMsgLen)
207 {
208 if (response == nullptr || !respMsgLen)
209 {
210 // Handle error scenario
211 error(
212 "No response received for pass component table for endpoint ID '{EID}'",
213 "EID", eid);
214 updateManager->updateDeviceCompletion(eid, false);
215 return;
216 }
217
218 uint8_t completionCode = 0;
219 uint8_t compResponse = 0;
220 uint8_t compResponseCode = 0;
221
222 auto rc =
223 decode_pass_component_table_resp(response, respMsgLen, &completionCode,
224 &compResponse, &compResponseCode);
225 if (rc)
226 {
227 // Handle error scenario
228 error(
229 "Failed to decode pass component table response for endpoint ID '{EID}', response code '{RC}'",
230 "EID", eid, "RC", rc);
231 return;
232 }
233 if (completionCode)
234 {
235 // Handle error scenario
236 error(
237 "Failed to pass component table response for endpoint ID '{EID}', completion code '{CC}'",
238 "EID", eid, "CC", completionCode);
239 updateManager->updateDeviceCompletion(eid, false);
240 return;
241 }
242 // Handle ComponentResponseCode
243
244 const auto& applicableComponents =
245 std::get<ApplicableComponents>(fwDeviceIDRecord);
246 if (componentIndex == applicableComponents.size() - 1)
247 {
248 componentIndex = 0;
249 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
250 updateManager->event,
251 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
252 componentIndex));
253 }
254 else
255 {
256 componentIndex++;
257 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
258 updateManager->event,
259 std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
260 componentIndex));
261 }
262 }
263
sendUpdateComponentRequest(size_t offset)264 void DeviceUpdater::sendUpdateComponentRequest(size_t offset)
265 {
266 pldmRequest.reset();
267
268 auto instanceId = updateManager->instanceIdDb.next(eid);
269 const auto& applicableComponents =
270 std::get<ApplicableComponents>(fwDeviceIDRecord);
271 const auto& comp = compImageInfos[applicableComponents[offset]];
272 // ComponentClassification
273 CompClassification compClassification = std::get<static_cast<size_t>(
274 ComponentImageInfoPos::CompClassificationPos)>(comp);
275 // ComponentIdentifier
276 CompIdentifier compIdentifier =
277 std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
278 comp);
279 // ComponentClassificationIndex
280 CompClassificationIndex compClassificationIndex{};
281 auto compKey = std::make_pair(compClassification, compIdentifier);
282 if (compInfo.contains(compKey))
283 {
284 auto search = compInfo.find(compKey);
285 compClassificationIndex = search->second;
286 }
287 else
288 {
289 // Handle error scenario
290 error(
291 "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
292 "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
293 }
294
295 // UpdateOptionFlags
296 bitfield32_t updateOptionFlags;
297 updateOptionFlags.bits.bit0 = std::get<3>(comp)[0];
298 // ComponentVersion
299 const auto& compVersion = std::get<7>(comp);
300 variable_field compVerStrInfo{};
301 compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
302 compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
303
304 Request request(
305 sizeof(pldm_msg_hdr) + sizeof(struct pldm_update_component_req) +
306 compVerStrInfo.length);
307 auto requestMsg = new (request.data()) pldm_msg;
308
309 auto rc = encode_update_component_req(
310 instanceId, compClassification, compIdentifier, compClassificationIndex,
311 std::get<static_cast<size_t>(
312 ComponentImageInfoPos::CompComparisonStampPos)>(comp),
313 std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(comp),
314 updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length,
315 &compVerStrInfo, requestMsg,
316 sizeof(pldm_update_component_req) + compVerStrInfo.length);
317 if (rc)
318 {
319 // Handle error scenario
320 updateManager->instanceIdDb.free(eid, instanceId);
321 error(
322 "Failed to encode update component req for endpoint ID '{EID}', response code '{RC}'",
323 "EID", eid, "RC", rc);
324 }
325
326 rc = updateManager->handler.registerRequest(
327 eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request),
328 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
329 this->updateComponent(eid, response, respMsgLen);
330 });
331 if (rc)
332 {
333 // Handle error scenario
334 error(
335 "Failed to send update request for endpoint ID '{EID}', response code '{RC}'",
336 "EID", eid, "RC", rc);
337 }
338 }
339
updateComponent(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)340 void DeviceUpdater::updateComponent(mctp_eid_t eid, const pldm_msg* response,
341 size_t respMsgLen)
342 {
343 if (response == nullptr || !respMsgLen)
344 {
345 // Handle error scenario
346 error(
347 "No response received for update component with endpoint ID {EID}",
348 "EID", eid);
349 updateManager->updateDeviceCompletion(eid, false);
350 return;
351 }
352
353 uint8_t completionCode = 0;
354 uint8_t compCompatibilityResp = 0;
355 uint8_t compCompatibilityRespCode = 0;
356 bitfield32_t updateOptionFlagsEnabled{};
357 uint16_t timeBeforeReqFWData = 0;
358
359 auto rc = decode_update_component_resp(
360 response, respMsgLen, &completionCode, &compCompatibilityResp,
361 &compCompatibilityRespCode, &updateOptionFlagsEnabled,
362 &timeBeforeReqFWData);
363 if (rc)
364 {
365 error(
366 "Failed to decode update request response for endpoint ID '{EID}', response code '{RC}'",
367 "EID", eid, "RC", rc);
368 return;
369 }
370 if (completionCode)
371 {
372 error(
373 "Failed to update request response for endpoint ID '{EID}', completion code '{CC}'",
374 "EID", eid, "CC", completionCode);
375 return;
376 updateManager->updateDeviceCompletion(eid, false);
377 }
378 }
379
createRequestFwDataTimer()380 void DeviceUpdater::createRequestFwDataTimer()
381 {
382 reqFwDataTimer = std::make_unique<sdbusplus::Timer>([this]() -> void {
383 componentUpdateStatus[componentIndex] = false;
384 sendCancelUpdateComponentRequest();
385 updateManager->updateDeviceCompletion(eid, false);
386 });
387 }
388
requestFwData(const pldm_msg * request,size_t payloadLength)389 Response DeviceUpdater::requestFwData(const pldm_msg* request,
390 size_t payloadLength)
391 {
392 uint8_t completionCode = PLDM_SUCCESS;
393 uint32_t offset = 0;
394 uint32_t length = 0;
395 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
396 auto responseMsg = new (response.data()) pldm_msg;
397 auto rc = decode_request_firmware_data_req(request, payloadLength, &offset,
398 &length);
399 if (rc)
400 {
401 error(
402 "Failed to decode request firmware date request for endpoint ID '{EID}', response code '{RC}'",
403 "EID", eid, "RC", rc);
404 rc = encode_request_firmware_data_resp(
405 request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg,
406 sizeof(completionCode));
407 if (rc)
408 {
409 error(
410 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
411 "EID", eid, "RC", rc);
412 }
413 return response;
414 }
415
416 const auto& applicableComponents =
417 std::get<ApplicableComponents>(fwDeviceIDRecord);
418 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
419 auto compOffset = std::get<5>(comp);
420 auto compSize = std::get<6>(comp);
421 debug("Decoded fw request data at offset '{OFFSET}' and length '{LENGTH}' ",
422 "OFFSET", offset, "LENGTH", length);
423 if (length < PLDM_FWUP_BASELINE_TRANSFER_SIZE || length > maxTransferSize)
424 {
425 rc = encode_request_firmware_data_resp(
426 request->hdr.instance_id, PLDM_FWUP_INVALID_TRANSFER_LENGTH,
427 responseMsg, sizeof(completionCode));
428 if (rc)
429 {
430 error(
431 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
432 "EID", eid, "RC", rc);
433 }
434 return response;
435 }
436
437 if (offset + length > compSize + PLDM_FWUP_BASELINE_TRANSFER_SIZE)
438 {
439 rc = encode_request_firmware_data_resp(
440 request->hdr.instance_id, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg,
441 sizeof(completionCode));
442 if (rc)
443 {
444 error(
445 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
446 "EID", eid, "RC", rc);
447 }
448 return response;
449 }
450
451 size_t padBytes = 0;
452 if (offset + length > compSize)
453 {
454 padBytes = offset + length - compSize;
455 }
456
457 response.resize(sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
458 responseMsg = new (response.data()) pldm_msg;
459 package.seekg(compOffset + offset);
460 package.read(
461 reinterpret_cast<char*>(
462 response.data() + sizeof(pldm_msg_hdr) + sizeof(completionCode)),
463 length - padBytes);
464 rc = encode_request_firmware_data_resp(
465 request->hdr.instance_id, completionCode, responseMsg,
466 sizeof(completionCode));
467 if (rc)
468 {
469 error(
470 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
471 "EID", eid, "RC", rc);
472 return response;
473 }
474
475 if (!reqFwDataTimer)
476 {
477 if (offset != 0)
478 {
479 warning("First data request is not at offset 0");
480 }
481 createRequestFwDataTimer();
482 }
483
484 if (reqFwDataTimer)
485 {
486 reqFwDataTimer->start(std::chrono::seconds(updateTimeoutSeconds),
487 false);
488 }
489 else
490 {
491 error(
492 "Failed to start timer for handling request firmware data for endpoint ID {EID}",
493 "EID", eid, "RC", rc);
494 }
495
496 return response;
497 }
498
transferComplete(const pldm_msg * request,size_t payloadLength)499 Response DeviceUpdater::transferComplete(const pldm_msg* request,
500 size_t payloadLength)
501 {
502 uint8_t completionCode = PLDM_SUCCESS;
503 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
504 auto responseMsg = new (response.data()) pldm_msg;
505
506 if (reqFwDataTimer)
507 {
508 reqFwDataTimer->stop();
509 reqFwDataTimer.reset();
510 }
511
512 uint8_t transferResult = 0;
513 auto rc =
514 decode_transfer_complete_req(request, payloadLength, &transferResult);
515 if (rc)
516 {
517 error(
518 "Failed to decode TransferComplete request for endpoint ID '{EID}', response code '{RC}'",
519 "EID", eid, "RC", rc);
520 rc = encode_transfer_complete_resp(request->hdr.instance_id,
521 PLDM_ERROR_INVALID_DATA, responseMsg,
522 sizeof(completionCode));
523 if (rc)
524 {
525 error(
526 "Failed to encode TransferComplete response for endpoint ID '{EID}', response code '{RC}'",
527 "EID", eid, "RC", rc);
528 }
529 return response;
530 }
531
532 const auto& applicableComponents =
533 std::get<ApplicableComponents>(fwDeviceIDRecord);
534 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
535 const auto& compVersion = std::get<7>(comp);
536
537 if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS)
538 {
539 info(
540 "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' transfer complete.",
541 "EID", eid, "COMPONENT_VERSION", compVersion);
542 }
543 else
544 {
545 error(
546 "Failure in transfer of the component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - {RESULT}",
547 "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT",
548 transferResult);
549 updateManager->updateDeviceCompletion(eid, false);
550 componentUpdateStatus[componentIndex] = false;
551 sendCancelUpdateComponentRequest();
552 }
553
554 rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode,
555 responseMsg, sizeof(completionCode));
556 if (rc)
557 {
558 error(
559 "Failed to encode transfer complete response of endpoint ID '{EID}', response code '{RC}'",
560 "EID", eid, "RC", rc);
561 return response;
562 }
563
564 return response;
565 }
566
verifyComplete(const pldm_msg * request,size_t payloadLength)567 Response DeviceUpdater::verifyComplete(const pldm_msg* request,
568 size_t payloadLength)
569 {
570 uint8_t completionCode = PLDM_SUCCESS;
571 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
572 auto responseMsg = new (response.data()) pldm_msg;
573
574 uint8_t verifyResult = 0;
575 auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult);
576 if (rc)
577 {
578 error(
579 "Failed to decode verify complete request of endpoint ID '{EID}', response code '{RC}'",
580 "EID", eid, "RC", rc);
581 rc = encode_verify_complete_resp(request->hdr.instance_id,
582 PLDM_ERROR_INVALID_DATA, responseMsg,
583 sizeof(completionCode));
584 if (rc)
585 {
586 error(
587 "Failed to encode verify complete response of endpoint ID '{EID}', response code '{RC}'.",
588 "EID", eid, "RC", rc);
589 }
590 return response;
591 }
592
593 const auto& applicableComponents =
594 std::get<ApplicableComponents>(fwDeviceIDRecord);
595 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
596 const auto& compVersion = std::get<7>(comp);
597
598 if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS)
599 {
600 info(
601 "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' verification complete.",
602 "EID", eid, "COMPONENT_VERSION", compVersion);
603 }
604 else
605 {
606 error(
607 "Failed to verify component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - '{RESULT}'",
608 "EID", eid, "COMPONENT_VERSION", compVersion, "RESULT",
609 verifyResult);
610 updateManager->updateDeviceCompletion(eid, false);
611 componentUpdateStatus[componentIndex] = false;
612 sendCancelUpdateComponentRequest();
613 }
614
615 rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode,
616 responseMsg, sizeof(completionCode));
617 if (rc)
618 {
619 error(
620 "Failed to encode verify complete response for endpoint ID '{EID}', response code - {RC}",
621 "EID", eid, "RC", rc);
622 return response;
623 }
624
625 return response;
626 }
627
applyComplete(const pldm_msg * request,size_t payloadLength)628 Response DeviceUpdater::applyComplete(const pldm_msg* request,
629 size_t payloadLength)
630 {
631 uint8_t completionCode = PLDM_SUCCESS;
632 Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
633 auto responseMsg = new (response.data()) pldm_msg;
634
635 uint8_t applyResult = 0;
636 bitfield16_t compActivationModification{};
637 auto rc = decode_apply_complete_req(request, payloadLength, &applyResult,
638 &compActivationModification);
639 if (rc)
640 {
641 error(
642 "Failed to decode apply complete request for endpoint ID '{EID}', response code '{RC}'",
643 "EID", eid, "RC", rc);
644 rc = encode_apply_complete_resp(request->hdr.instance_id,
645 PLDM_ERROR_INVALID_DATA, responseMsg,
646 sizeof(completionCode));
647 if (rc)
648 {
649 error(
650 "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
651 "EID", eid, "RC", rc);
652 }
653 return response;
654 }
655
656 const auto& applicableComponents =
657 std::get<ApplicableComponents>(fwDeviceIDRecord);
658 const auto& comp = compImageInfos[applicableComponents[componentIndex]];
659 const auto& compVersion = std::get<7>(comp);
660
661 if (applyResult == PLDM_FWUP_APPLY_SUCCESS ||
662 applyResult == PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD)
663 {
664 info(
665 "Component endpoint ID '{EID}' with '{COMPONENT_VERSION}' apply complete.",
666 "EID", eid, "COMPONENT_VERSION", compVersion);
667 updateManager->updateActivationProgress();
668 if (componentIndex == applicableComponents.size() - 1)
669 {
670 componentIndex = 0;
671 componentUpdateStatus.clear();
672 componentUpdateStatus[componentIndex] = true;
673 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
674 updateManager->event,
675 std::bind(&DeviceUpdater::sendActivateFirmwareRequest, this));
676 }
677 else
678 {
679 componentIndex++;
680 componentUpdateStatus[componentIndex] = true;
681 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
682 updateManager->event,
683 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
684 componentIndex));
685 }
686 }
687 else
688 {
689 error(
690 "Failed to apply component endpoint ID '{EID}' and version '{COMPONENT_VERSION}', error - {ERROR}",
691 "EID", eid, "COMPONENT_VERSION", compVersion, "ERROR", applyResult);
692 updateManager->updateDeviceCompletion(eid, false);
693 componentUpdateStatus[componentIndex] = false;
694 sendCancelUpdateComponentRequest();
695 }
696
697 rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode,
698 responseMsg, sizeof(completionCode));
699 if (rc)
700 {
701 error(
702 "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
703 "EID", eid, "RC", rc);
704 return response;
705 }
706
707 return response;
708 }
709
sendActivateFirmwareRequest()710 void DeviceUpdater::sendActivateFirmwareRequest()
711 {
712 pldmRequest.reset();
713 auto instanceId = updateManager->instanceIdDb.next(eid);
714 Request request(
715 sizeof(pldm_msg_hdr) + sizeof(struct pldm_activate_firmware_req));
716 auto requestMsg = new (request.data()) pldm_msg;
717
718 auto rc = encode_activate_firmware_req(
719 instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,
720 sizeof(pldm_activate_firmware_req));
721 if (rc)
722 {
723 updateManager->instanceIdDb.free(eid, instanceId);
724 error(
725 "Failed to encode activate firmware req for endpoint ID '{EID}', response code '{RC}'",
726 "EID", eid, "RC", rc);
727 }
728
729 rc = updateManager->handler.registerRequest(
730 eid, instanceId, PLDM_FWUP, PLDM_ACTIVATE_FIRMWARE, std::move(request),
731 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
732 this->activateFirmware(eid, response, respMsgLen);
733 });
734 if (rc)
735 {
736 error(
737 "Failed to send activate firmware request for endpoint ID '{EID}', response code '{RC}'",
738 "EID", eid, "RC", rc);
739 }
740 }
741
activateFirmware(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)742 void DeviceUpdater::activateFirmware(mctp_eid_t eid, const pldm_msg* response,
743 size_t respMsgLen)
744 {
745 if (response == nullptr || !respMsgLen)
746 {
747 // Handle error scenario
748 error(
749 "No response received for activate firmware for endpoint ID '{EID}'",
750 "EID", eid);
751 updateManager->updateDeviceCompletion(eid, false);
752 return;
753 }
754
755 uint8_t completionCode = 0;
756 uint16_t estimatedTimeForActivation = 0;
757
758 auto rc = decode_activate_firmware_resp(
759 response, respMsgLen, &completionCode, &estimatedTimeForActivation);
760 if (rc)
761 {
762 // Handle error scenario
763 error(
764 "Failed to decode activate firmware response for endpoint ID '{EID}', response code '{RC}'",
765 "EID", eid, "RC", rc);
766 return;
767 }
768 if (completionCode)
769 {
770 // Handle error scenario
771 error(
772 "Failed to activate firmware response for endpoint ID '{EID}', completion code '{CC}'",
773 "EID", eid, "CC", completionCode);
774 updateManager->updateDeviceCompletion(eid, false);
775 return;
776 }
777
778 updateManager->updateDeviceCompletion(eid, true);
779 }
780
sendCancelUpdateComponentRequest()781 void DeviceUpdater::sendCancelUpdateComponentRequest()
782 {
783 pldmRequest.reset();
784 auto instanceId = updateManager->instanceIdDb.next(eid);
785 Request request(sizeof(pldm_msg_hdr));
786 auto requestMsg = new (request.data()) pldm_msg;
787
788 auto rc = encode_cancel_update_component_req(
789 instanceId, requestMsg, PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES);
790 if (rc)
791 {
792 updateManager->instanceIdDb.free(eid, instanceId);
793 error(
794 "Failed to encode cancel update component request for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', response code '{RC}'",
795 "EID", eid, "COMPONENT_INDEX", componentIndex, "RC", rc);
796 return;
797 }
798
799 rc = updateManager->handler.registerRequest(
800 eid, instanceId, PLDM_FWUP, PLDM_CANCEL_UPDATE_COMPONENT,
801 std::move(request),
802 [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
803 this->cancelUpdateComponent(eid, response, respMsgLen);
804 });
805 if (rc)
806 {
807 error(
808 "Failed to send cancel update component request for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', response code '{RC}'",
809 "EID", eid, "COMPONENT_INDEX", componentIndex, "RC", rc);
810 }
811 }
812
cancelUpdateComponent(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)813 void DeviceUpdater::cancelUpdateComponent(
814 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
815 {
816 // Check if response is valid
817 if (response == nullptr || !respMsgLen)
818 {
819 error(
820 "No response received for cancel update component for endpoint ID '{EID}'",
821 "EID", eid);
822 return;
823 }
824
825 uint8_t completionCode = 0;
826 auto rc = decode_cancel_update_component_resp(response, respMsgLen,
827 &completionCode);
828 if (rc)
829 {
830 error(
831 "Failed to decode cancel update component response for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', completion code '{CC}'",
832 "EID", eid, "COMPONENT_INDEX", componentIndex, "CC",
833 completionCode);
834 return;
835 }
836 if (completionCode)
837 {
838 error(
839 "Failed to cancel update component for endpoint ID '{EID}', component index '{COMPONENT_INDEX}', completion code '{CC}'",
840 "EID", eid, "COMPONENT_INDEX", componentIndex, "CC",
841 completionCode);
842 return;
843 }
844
845 const auto& applicableComponents =
846 std::get<ApplicableComponents>(fwDeviceIDRecord);
847 // Check if this is the last component being cancelled
848 if (componentIndex == applicableComponents.size() - 1)
849 {
850 for (auto& compStatus : componentUpdateStatus)
851 {
852 if (compStatus.second)
853 {
854 // If at least one component update succeeded, proceed with
855 // activation
856 componentIndex = 0;
857 componentUpdateStatus.clear();
858 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
859 updateManager->event,
860 std::bind(&DeviceUpdater::sendActivateFirmwareRequest,
861 this));
862 return;
863 }
864 }
865 updateManager->updateDeviceCompletion(eid, false);
866 }
867 else
868 {
869 // Move to next component and update its status
870 componentIndex++;
871 componentUpdateStatus[componentIndex] = true;
872 pldmRequest = std::make_unique<sdeventplus::source::Defer>(
873 updateManager->event,
874 std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
875 componentIndex));
876 }
877 return;
878 }
879
880 } // namespace fw_update
881
882 } // namespace pldm
883