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