xref: /openbmc/pldm/fw-update/device_updater.cpp (revision 6fa09e9621b4e8ad3f4ed935a23f665ec9bcfed8)
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