xref: /openbmc/pldm/fw-update/device_updater.cpp (revision 9e4aedb7)
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 
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(sizeof(pldm_msg_hdr) +
39                     sizeof(struct pldm_request_update_req) +
40                     compImgSetVerStrInfo.length);
41     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
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", unsigned(eid), "RC", rc);
56     }
57 
58     rc = updateManager->handler.registerRequest(
59         eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request),
60         std::move(std::bind_front(&DeviceUpdater::requestUpdate, this)));
61     if (rc)
62     {
63         // Handle error scenario
64         error(
65             "Failed to send request update for endpoint ID '{EID}', response code '{RC}'",
66             "EID", unsigned(eid), "RC", rc);
67     }
68 }
69 
70 void DeviceUpdater::requestUpdate(mctp_eid_t eid, const pldm_msg* response,
71                                   size_t respMsgLen)
72 {
73     if (response == nullptr || !respMsgLen)
74     {
75         // Handle error scenario
76         error("No response received for request update for endpoint ID '{EID}'",
77               "EID", unsigned(eid));
78         return;
79     }
80 
81     uint8_t completionCode = 0;
82     uint16_t fdMetaDataLen = 0;
83     uint8_t fdWillSendPkgData = 0;
84 
85     auto rc = decode_request_update_resp(response, respMsgLen, &completionCode,
86                                          &fdMetaDataLen, &fdWillSendPkgData);
87     if (rc)
88     {
89         error(
90             "Failed to decode request update response for endpoint ID '{EID}', response code '{RC}'",
91             "EID", unsigned(eid), "RC", rc);
92         return;
93     }
94     if (completionCode)
95     {
96         error(
97             "Failure in request update response for endpoint ID '{EID}', completion code '{CC}'",
98             "EID", unsigned(eid), "CC", unsigned(completionCode));
99         return;
100     }
101 
102     // Optional fields DeviceMetaData and GetPackageData not handled
103     pldmRequest = std::make_unique<sdeventplus::source::Defer>(
104         updateManager->event,
105         std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
106                   componentIndex));
107 }
108 
109 void DeviceUpdater::sendPassCompTableRequest(size_t offset)
110 {
111     pldmRequest.reset();
112 
113     auto instanceId = updateManager->instanceIdDb.next(eid);
114     // TransferFlag
115     const auto& applicableComponents =
116         std::get<ApplicableComponents>(fwDeviceIDRecord);
117     uint8_t transferFlag = 0;
118     if (applicableComponents.size() == 1)
119     {
120         transferFlag = PLDM_START_AND_END;
121     }
122     else if (offset == 0)
123     {
124         transferFlag = PLDM_START;
125     }
126     else if (offset == applicableComponents.size() - 1)
127     {
128         transferFlag = PLDM_END;
129     }
130     else
131     {
132         transferFlag = PLDM_MIDDLE;
133     }
134     const auto& comp = compImageInfos[applicableComponents[offset]];
135     // ComponentClassification
136     CompClassification compClassification = std::get<static_cast<size_t>(
137         ComponentImageInfoPos::CompClassificationPos)>(comp);
138     // ComponentIdentifier
139     CompIdentifier compIdentifier =
140         std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
141             comp);
142     // ComponentClassificationIndex
143     CompClassificationIndex compClassificationIndex{};
144     auto compKey = std::make_pair(compClassification, compIdentifier);
145     if (compInfo.contains(compKey))
146     {
147         auto search = compInfo.find(compKey);
148         compClassificationIndex = search->second;
149     }
150     else
151     {
152         // Handle error scenario
153         error(
154             "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
155             "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
156     }
157     // ComponentComparisonStamp
158     CompComparisonStamp compComparisonStamp = std::get<static_cast<size_t>(
159         ComponentImageInfoPos::CompComparisonStampPos)>(comp);
160     // ComponentVersionString
161     const auto& compVersion =
162         std::get<static_cast<size_t>(ComponentImageInfoPos::CompVersionPos)>(
163             comp);
164     variable_field compVerStrInfo{};
165     compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
166     compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
167 
168     Request request(sizeof(pldm_msg_hdr) +
169                     sizeof(struct pldm_pass_component_table_req) +
170                     compVerStrInfo.length);
171     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
172     auto rc = encode_pass_component_table_req(
173         instanceId, transferFlag, compClassification, compIdentifier,
174         compClassificationIndex, compComparisonStamp, PLDM_STR_TYPE_ASCII,
175         compVerStrInfo.length, &compVerStrInfo, requestMsg,
176         sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
177     if (rc)
178     {
179         // Handle error scenario
180         updateManager->instanceIdDb.free(eid, instanceId);
181         error(
182             "Failed to encode pass component table req for endpoint ID '{EID}', response code '{RC}'",
183             "EID", unsigned(eid), "RC", rc);
184     }
185 
186     rc = updateManager->handler.registerRequest(
187         eid, instanceId, PLDM_FWUP, PLDM_PASS_COMPONENT_TABLE,
188         std::move(request),
189         std::move(std::bind_front(&DeviceUpdater::passCompTable, this)));
190     if (rc)
191     {
192         // Handle error scenario
193         error(
194             "Failed to send pass component table request for endpoint ID '{EID}', response code '{RC}'",
195             "EID", unsigned(eid), "RC", rc);
196     }
197 }
198 
199 void DeviceUpdater::passCompTable(mctp_eid_t eid, const pldm_msg* response,
200                                   size_t respMsgLen)
201 {
202     if (response == nullptr || !respMsgLen)
203     {
204         // Handle error scenario
205         error(
206             "No response received for pass component table for endpoint ID '{EID}'",
207             "EID", unsigned(eid));
208         return;
209     }
210 
211     uint8_t completionCode = 0;
212     uint8_t compResponse = 0;
213     uint8_t compResponseCode = 0;
214 
215     auto rc = decode_pass_component_table_resp(response, respMsgLen,
216                                                &completionCode, &compResponse,
217                                                &compResponseCode);
218     if (rc)
219     {
220         // Handle error scenario
221         error(
222             "Failed to decode pass component table response for endpoint ID '{EID}', response code '{RC}'",
223             "EID", unsigned(eid), "RC", rc);
224         return;
225     }
226     if (completionCode)
227     {
228         // Handle error scenario
229         error(
230             "Failed to pass component table response for endpoint ID '{EID}', completion code '{CC}'",
231             "EID", unsigned(eid), "CC", unsigned(completionCode));
232         return;
233     }
234     // Handle ComponentResponseCode
235 
236     const auto& applicableComponents =
237         std::get<ApplicableComponents>(fwDeviceIDRecord);
238     if (componentIndex == applicableComponents.size() - 1)
239     {
240         componentIndex = 0;
241         pldmRequest = std::make_unique<sdeventplus::source::Defer>(
242             updateManager->event,
243             std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
244                       componentIndex));
245     }
246     else
247     {
248         componentIndex++;
249         pldmRequest = std::make_unique<sdeventplus::source::Defer>(
250             updateManager->event,
251             std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
252                       componentIndex));
253     }
254 }
255 
256 void DeviceUpdater::sendUpdateComponentRequest(size_t offset)
257 {
258     pldmRequest.reset();
259 
260     auto instanceId = updateManager->instanceIdDb.next(eid);
261     const auto& applicableComponents =
262         std::get<ApplicableComponents>(fwDeviceIDRecord);
263     const auto& comp = compImageInfos[applicableComponents[offset]];
264     // ComponentClassification
265     CompClassification compClassification = std::get<static_cast<size_t>(
266         ComponentImageInfoPos::CompClassificationPos)>(comp);
267     // ComponentIdentifier
268     CompIdentifier compIdentifier =
269         std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
270             comp);
271     // ComponentClassificationIndex
272     CompClassificationIndex compClassificationIndex{};
273     auto compKey = std::make_pair(compClassification, compIdentifier);
274     if (compInfo.contains(compKey))
275     {
276         auto search = compInfo.find(compKey);
277         compClassificationIndex = search->second;
278     }
279     else
280     {
281         // Handle error scenario
282         error(
283             "Failed to find component classification '{CLASSIFICATION}' and identifier '{IDENTIFIER}'",
284             "CLASSIFICATION", compClassification, "IDENTIFIER", compIdentifier);
285     }
286 
287     // UpdateOptionFlags
288     bitfield32_t updateOptionFlags;
289     updateOptionFlags.bits.bit0 = std::get<3>(comp)[0];
290     // ComponentVersion
291     const auto& compVersion = std::get<7>(comp);
292     variable_field compVerStrInfo{};
293     compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
294     compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
295 
296     Request request(sizeof(pldm_msg_hdr) +
297                     sizeof(struct pldm_update_component_req) +
298                     compVerStrInfo.length);
299     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
300 
301     auto rc = encode_update_component_req(
302         instanceId, compClassification, compIdentifier, compClassificationIndex,
303         std::get<static_cast<size_t>(
304             ComponentImageInfoPos::CompComparisonStampPos)>(comp),
305         std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(comp),
306         updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length,
307         &compVerStrInfo, requestMsg,
308         sizeof(pldm_update_component_req) + compVerStrInfo.length);
309     if (rc)
310     {
311         // Handle error scenario
312         updateManager->instanceIdDb.free(eid, instanceId);
313         error(
314             "Failed to encode update component req for endpoint ID '{EID}', response code '{RC}'",
315             "EID", unsigned(eid), "RC", rc);
316     }
317 
318     rc = updateManager->handler.registerRequest(
319         eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request),
320         std::move(std::bind_front(&DeviceUpdater::updateComponent, this)));
321     if (rc)
322     {
323         // Handle error scenario
324         error(
325             "Failed to send update request for endpoint ID '{EID}', response code '{RC}'",
326             "EID", unsigned(eid), "RC", rc);
327     }
328 }
329 
330 void DeviceUpdater::updateComponent(mctp_eid_t eid, const pldm_msg* response,
331                                     size_t respMsgLen)
332 {
333     if (response == nullptr || !respMsgLen)
334     {
335         // Handle error scenario
336         error(
337             "No response received for update component with endpoint ID {EID}",
338             "EID", unsigned(eid));
339         return;
340     }
341 
342     uint8_t completionCode = 0;
343     uint8_t compCompatibilityResp = 0;
344     uint8_t compCompatibilityRespCode = 0;
345     bitfield32_t updateOptionFlagsEnabled{};
346     uint16_t timeBeforeReqFWData = 0;
347 
348     auto rc = decode_update_component_resp(
349         response, respMsgLen, &completionCode, &compCompatibilityResp,
350         &compCompatibilityRespCode, &updateOptionFlagsEnabled,
351         &timeBeforeReqFWData);
352     if (rc)
353     {
354         error(
355             "Failed to decode update request response for endpoint ID '{EID}', response code '{RC}'",
356             "EID", unsigned(eid), "RC", rc);
357         return;
358     }
359     if (completionCode)
360     {
361         error(
362             "Failed to update request response for endpoint ID '{EID}', completion code '{CC}'",
363             "EID", unsigned(eid), "CC", unsigned(completionCode));
364         return;
365     }
366 }
367 
368 Response DeviceUpdater::requestFwData(const pldm_msg* request,
369                                       size_t payloadLength)
370 {
371     uint8_t completionCode = PLDM_SUCCESS;
372     uint32_t offset = 0;
373     uint32_t length = 0;
374     Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
375     auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
376     auto rc = decode_request_firmware_data_req(request, payloadLength, &offset,
377                                                &length);
378     if (rc)
379     {
380         error(
381             "Failed to decode request firmware date request for endpoint ID '{EID}', response code '{RC}'",
382             "EID", unsigned(eid), "RC", rc);
383         rc = encode_request_firmware_data_resp(
384             request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg,
385             sizeof(completionCode));
386         if (rc)
387         {
388             error(
389                 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
390                 "EID", unsigned(eid), "RC", rc);
391         }
392         return response;
393     }
394 
395     const auto& applicableComponents =
396         std::get<ApplicableComponents>(fwDeviceIDRecord);
397     const auto& comp = compImageInfos[applicableComponents[componentIndex]];
398     auto compOffset = std::get<5>(comp);
399     auto compSize = std::get<6>(comp);
400     info("Decoded fw request data at offset '{OFFSET}' and length '{LENGTH}' ",
401          "OFFSET", unsigned(offset), "LENGTH", unsigned(length));
402     if (length < PLDM_FWUP_BASELINE_TRANSFER_SIZE || length > maxTransferSize)
403     {
404         rc = encode_request_firmware_data_resp(
405             request->hdr.instance_id, PLDM_FWUP_INVALID_TRANSFER_LENGTH,
406             responseMsg, 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", unsigned(eid), "RC", rc);
412         }
413         return response;
414     }
415 
416     if (offset + length > compSize + PLDM_FWUP_BASELINE_TRANSFER_SIZE)
417     {
418         rc = encode_request_firmware_data_resp(
419             request->hdr.instance_id, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg,
420             sizeof(completionCode));
421         if (rc)
422         {
423             error(
424                 "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
425                 "EID", unsigned(eid), "RC", rc);
426         }
427         return response;
428     }
429 
430     size_t padBytes = 0;
431     if (offset + length > compSize)
432     {
433         padBytes = offset + length - compSize;
434     }
435 
436     response.resize(sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
437     responseMsg = reinterpret_cast<pldm_msg*>(response.data());
438     package.seekg(compOffset + offset);
439     package.read(reinterpret_cast<char*>(response.data() +
440                                          sizeof(pldm_msg_hdr) +
441                                          sizeof(completionCode)),
442                  length - padBytes);
443     rc = encode_request_firmware_data_resp(request->hdr.instance_id,
444                                            completionCode, responseMsg,
445                                            sizeof(completionCode));
446     if (rc)
447     {
448         error(
449             "Failed to encode request firmware date response for endpoint ID '{EID}', response code '{RC}'",
450             "EID", unsigned(eid), "RC", rc);
451         return response;
452     }
453 
454     return response;
455 }
456 
457 Response DeviceUpdater::transferComplete(const pldm_msg* request,
458                                          size_t payloadLength)
459 {
460     uint8_t completionCode = PLDM_SUCCESS;
461     Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
462     auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
463 
464     uint8_t transferResult = 0;
465     auto rc = decode_transfer_complete_req(request, payloadLength,
466                                            &transferResult);
467     if (rc)
468     {
469         error(
470             "Failed to decode TransferComplete request for endpoint ID '{EID}', response code '{RC}'",
471             "EID", unsigned(eid), "RC", rc);
472         rc = encode_transfer_complete_resp(request->hdr.instance_id,
473                                            PLDM_ERROR_INVALID_DATA, responseMsg,
474                                            sizeof(completionCode));
475         if (rc)
476         {
477             error(
478                 "Failed to encode TransferComplete response for endpoint ID '{EID}', response code '{RC}'",
479                 "EID", unsigned(eid), "RC", rc);
480         }
481         return response;
482     }
483 
484     const auto& applicableComponents =
485         std::get<ApplicableComponents>(fwDeviceIDRecord);
486     const auto& comp = compImageInfos[applicableComponents[componentIndex]];
487     const auto& compVersion = std::get<7>(comp);
488 
489     if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS)
490     {
491         info(
492             "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' transfer complete.",
493             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion);
494     }
495     else
496     {
497         error(
498             "Failure in transfer of the component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - {RESULT}",
499             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion, "RESULT",
500             unsigned(transferResult));
501     }
502 
503     rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode,
504                                        responseMsg, sizeof(completionCode));
505     if (rc)
506     {
507         error(
508             "Failed to encode transfer complete response of endpoint ID '{EID}', response code '{RC}'",
509             "EID", unsigned(eid), "RC", rc);
510         return response;
511     }
512 
513     return response;
514 }
515 
516 Response DeviceUpdater::verifyComplete(const pldm_msg* request,
517                                        size_t payloadLength)
518 {
519     uint8_t completionCode = PLDM_SUCCESS;
520     Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
521     auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
522 
523     uint8_t verifyResult = 0;
524     auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult);
525     if (rc)
526     {
527         error(
528             "Failed to decode verify complete request of endpoint ID '{EID}', response code '{RC}'",
529             "EID", unsigned(eid), "RC", rc);
530         rc = encode_verify_complete_resp(request->hdr.instance_id,
531                                          PLDM_ERROR_INVALID_DATA, responseMsg,
532                                          sizeof(completionCode));
533         if (rc)
534         {
535             error(
536                 "Failed to encode verify complete response of endpoint ID '{EID}', response code '{RC}'.",
537                 "EID", unsigned(eid), "RC", rc);
538         }
539         return response;
540     }
541 
542     const auto& applicableComponents =
543         std::get<ApplicableComponents>(fwDeviceIDRecord);
544     const auto& comp = compImageInfos[applicableComponents[componentIndex]];
545     const auto& compVersion = std::get<7>(comp);
546 
547     if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS)
548     {
549         info(
550             "Component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' verification complete.",
551             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion);
552     }
553     else
554     {
555         error(
556             "Failed to verify component endpoint ID '{EID}' and version '{COMPONENT_VERSION}' with transfer result - '{RESULT}'",
557             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion, "RESULT",
558             unsigned(verifyResult));
559     }
560 
561     rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode,
562                                      responseMsg, sizeof(completionCode));
563     if (rc)
564     {
565         error(
566             "Failed to encode verify complete response for endpoint ID '{EID}', response code - {RC}",
567             "EID", unsigned(eid), "RC", rc);
568         return response;
569     }
570 
571     return response;
572 }
573 
574 Response DeviceUpdater::applyComplete(const pldm_msg* request,
575                                       size_t payloadLength)
576 {
577     uint8_t completionCode = PLDM_SUCCESS;
578     Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
579     auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
580 
581     uint8_t applyResult = 0;
582     bitfield16_t compActivationModification{};
583     auto rc = decode_apply_complete_req(request, payloadLength, &applyResult,
584                                         &compActivationModification);
585     if (rc)
586     {
587         error(
588             "Failed to decode apply complete request for endpoint ID '{EID}', response code '{RC}'",
589             "EID", unsigned(eid), "RC", rc);
590         rc = encode_apply_complete_resp(request->hdr.instance_id,
591                                         PLDM_ERROR_INVALID_DATA, responseMsg,
592                                         sizeof(completionCode));
593         if (rc)
594         {
595             error(
596                 "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
597                 "EID", unsigned(eid), "RC", rc);
598         }
599         return response;
600     }
601 
602     const auto& applicableComponents =
603         std::get<ApplicableComponents>(fwDeviceIDRecord);
604     const auto& comp = compImageInfos[applicableComponents[componentIndex]];
605     const auto& compVersion = std::get<7>(comp);
606 
607     if (applyResult == PLDM_FWUP_APPLY_SUCCESS ||
608         applyResult == PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD)
609     {
610         info(
611             "Component endpoint ID '{EID}' with '{COMPONENT_VERSION}' apply complete.",
612             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion);
613         updateManager->updateActivationProgress();
614     }
615     else
616     {
617         error(
618             "Failed to apply component endpoint ID '{EID}' and version '{COMPONENT_VERSION}', error - {ERROR}",
619             "EID", unsigned(eid), "COMPONENT_VERSION", compVersion, "ERROR",
620             unsigned(applyResult));
621     }
622 
623     rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode,
624                                     responseMsg, sizeof(completionCode));
625     if (rc)
626     {
627         error(
628             "Failed to encode apply complete response for endpoint ID '{EID}', response code '{RC}'",
629             "EID", unsigned(eid), "RC", rc);
630         return response;
631     }
632 
633     if (componentIndex == applicableComponents.size() - 1)
634     {
635         componentIndex = 0;
636         pldmRequest = std::make_unique<sdeventplus::source::Defer>(
637             updateManager->event,
638             std::bind(&DeviceUpdater::sendActivateFirmwareRequest, this));
639     }
640     else
641     {
642         componentIndex++;
643         pldmRequest = std::make_unique<sdeventplus::source::Defer>(
644             updateManager->event,
645             std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
646                       componentIndex));
647     }
648 
649     return response;
650 }
651 
652 void DeviceUpdater::sendActivateFirmwareRequest()
653 {
654     pldmRequest.reset();
655     auto instanceId = updateManager->instanceIdDb.next(eid);
656     Request request(sizeof(pldm_msg_hdr) +
657                     sizeof(struct pldm_activate_firmware_req));
658     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
659 
660     auto rc = encode_activate_firmware_req(
661         instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,
662         sizeof(pldm_activate_firmware_req));
663     if (rc)
664     {
665         updateManager->instanceIdDb.free(eid, instanceId);
666         error(
667             "Failed to encode activate firmware req for endpoint ID '{EID}', response code '{RC}'",
668             "EID", unsigned(eid), "RC", rc);
669     }
670 
671     rc = updateManager->handler.registerRequest(
672         eid, instanceId, PLDM_FWUP, PLDM_ACTIVATE_FIRMWARE, std::move(request),
673         std::move(std::bind_front(&DeviceUpdater::activateFirmware, this)));
674     if (rc)
675     {
676         error(
677             "Failed to send activate firmware request for endpoint ID '{EID}', response code '{RC}'",
678             "EID", unsigned(eid), "RC", rc);
679     }
680 }
681 
682 void DeviceUpdater::activateFirmware(mctp_eid_t eid, const pldm_msg* response,
683                                      size_t respMsgLen)
684 {
685     if (response == nullptr || !respMsgLen)
686     {
687         // Handle error scenario
688         error(
689             "No response received for activate firmware for endpoint ID '{EID}'",
690             "EID", eid);
691         return;
692     }
693 
694     uint8_t completionCode = 0;
695     uint16_t estimatedTimeForActivation = 0;
696 
697     auto rc = decode_activate_firmware_resp(
698         response, respMsgLen, &completionCode, &estimatedTimeForActivation);
699     if (rc)
700     {
701         // Handle error scenario
702         error(
703             "Failed to decode activate firmware response for endpoint ID '{EID}', response code '{RC}'",
704             "EID", eid, "RC", rc);
705         return;
706     }
707     if (completionCode)
708     {
709         // Handle error scenario
710         error(
711             "Failed to activate firmware response for endpoint ID '{EID}', completion code '{CC}'",
712             "EID", eid, "CC", completionCode);
713         return;
714     }
715 
716     updateManager->updateDeviceCompletion(eid, true);
717 }
718 
719 } // namespace fw_update
720 
721 } // namespace pldm
722