fw-update: Implement DeviceUpdater

The DeviceUpdater class implements the firmware update of a FD. The
firmware update flow is implemented as per DSP0267_1.0.0 and
DSP0267_1.0.1. All the components applicable for the FD is updated.
This patch doesn't handle error response codes and the further actions
to the firmware update flow. The optional features of package like package
data and device metadata is not included in this patch. Timeouts and retries
of firmware update commands is not included in this patch.

Tested: Added unit tests for the firmware update commands where PLDM
UA is the responder like RequestFirmwareData, TransferComplete,
VerifyComplete and ApplyComplete.

Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: If686ca005230d6debc0a6fd2ee73184bd3c28ee1
diff --git a/fw-update/device_updater.cpp b/fw-update/device_updater.cpp
new file mode 100644
index 0000000..c8605f4
--- /dev/null
+++ b/fw-update/device_updater.cpp
@@ -0,0 +1,671 @@
+#include "device_updater.hpp"
+
+#include "libpldm/firmware_update.h"
+
+#include <functional>
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+void DeviceUpdater::startFwUpdateFlow()
+{
+    auto instanceId = requester.getInstanceId(eid);
+    // NumberOfComponents
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    // PackageDataLength
+    const auto& fwDevicePkgData =
+        std::get<FirmwareDevicePackageData>(fwDeviceIDRecord);
+    // ComponentImageSetVersionString
+    const auto& compImageSetVersion =
+        std::get<ComponentImageSetVersion>(fwDeviceIDRecord);
+    variable_field compImgSetVerStrInfo{};
+    compImgSetVerStrInfo.ptr =
+        reinterpret_cast<const uint8_t*>(compImageSetVersion.data());
+    compImgSetVerStrInfo.length =
+        static_cast<uint8_t>(compImageSetVersion.size());
+
+    Request request(sizeof(pldm_msg_hdr) +
+                    sizeof(struct pldm_request_update_req) +
+                    compImgSetVerStrInfo.length);
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+
+    auto rc = encode_request_update_req(
+        instanceId, maxTransferSize, applicableComponents.size(),
+        PLDM_FWUP_MIN_OUTSTANDING_REQ, fwDevicePkgData.size(),
+        PLDM_STR_TYPE_ASCII, compImgSetVerStrInfo.length, &compImgSetVerStrInfo,
+        requestMsg,
+        sizeof(struct pldm_request_update_req) + compImgSetVerStrInfo.length);
+    if (rc)
+    {
+        requester.markFree(eid, instanceId);
+        std::cerr << "encode_request_update_req failed, EID=" << unsigned(eid)
+                  << ", RC=" << rc << "\n";
+        // Handle error scenario
+    }
+
+    rc = handler.registerRequest(
+        eid, instanceId, PLDM_FWUP, PLDM_REQUEST_UPDATE, std::move(request),
+        std::move(std::bind_front(&DeviceUpdater::requestUpdate, this)));
+    if (rc)
+    {
+        std::cerr << "Failed to send RequestUpdate request, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n ";
+        // Handle error scenario
+    }
+}
+
+void DeviceUpdater::requestUpdate(mctp_eid_t eid, const pldm_msg* response,
+                                  size_t respMsgLen)
+{
+    if (response == nullptr || !respMsgLen)
+    {
+        // Handle error scenario
+        std::cerr << "No response received for RequestUpdate, EID="
+                  << unsigned(eid) << "\n";
+        return;
+    }
+
+    uint8_t completionCode = 0;
+    uint16_t fdMetaDataLen = 0;
+    uint8_t fdWillSendPkgData = 0;
+
+    auto rc = decode_request_update_resp(response, respMsgLen, &completionCode,
+                                         &fdMetaDataLen, &fdWillSendPkgData);
+    if (rc)
+    {
+        std::cerr << "Decoding RequestUpdate response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return;
+    }
+    if (completionCode)
+    {
+        std::cerr << "RequestUpdate response failed with error "
+                     "completion code, EID="
+                  << unsigned(eid) << ", CC=" << unsigned(completionCode)
+                  << "\n";
+        return;
+    }
+
+    // Optional fields DeviceMetaData and GetPackageData not handled
+    pldmRequest = std::make_unique<sdeventplus::source::Defer>(
+        event, std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
+                         componentIndex));
+}
+
+void DeviceUpdater::sendPassCompTableRequest(size_t offset)
+{
+    pldmRequest.reset();
+
+    auto instanceId = requester.getInstanceId(eid);
+    // TransferFlag
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    uint8_t transferFlag = 0;
+    if (applicableComponents.size() == 1)
+    {
+        transferFlag = PLDM_START_AND_END;
+    }
+    else if (offset == 0)
+    {
+        transferFlag = PLDM_START;
+    }
+    else if (offset == applicableComponents.size() - 1)
+    {
+        transferFlag = PLDM_END;
+    }
+    else
+    {
+        transferFlag = PLDM_MIDDLE;
+    }
+    const auto& comp = compImageInfos[applicableComponents[offset]];
+    // ComponentClassification
+    CompClassification compClassification = std::get<static_cast<size_t>(
+        ComponentImageInfoPos::CompClassificationPos)>(comp);
+    // ComponentIdentifier
+    CompIdentifier compIdentifier =
+        std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
+            comp);
+    // ComponentClassificationIndex
+    CompClassificationIndex compClassificationIndex{};
+    auto compKey = std::make_pair(compClassification, compIdentifier);
+    if (compInfo.contains(compKey))
+    {
+        auto search = compInfo.find(compKey);
+        compClassificationIndex = search->second;
+    }
+    else
+    {
+        // Handle error scenario
+    }
+    // ComponentComparisonStamp
+    CompComparisonStamp compComparisonStamp = std::get<static_cast<size_t>(
+        ComponentImageInfoPos::CompComparisonStampPos)>(comp);
+    // ComponentVersionString
+    const auto& compVersion =
+        std::get<static_cast<size_t>(ComponentImageInfoPos::CompVersionPos)>(
+            comp);
+    variable_field compVerStrInfo{};
+    compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
+    compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
+
+    Request request(sizeof(pldm_msg_hdr) +
+                    sizeof(struct pldm_pass_component_table_req) +
+                    compVerStrInfo.length);
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+    auto rc = encode_pass_component_table_req(
+        instanceId, transferFlag, compClassification, compIdentifier,
+        compClassificationIndex, compComparisonStamp, PLDM_STR_TYPE_ASCII,
+        compVerStrInfo.length, &compVerStrInfo, requestMsg,
+        sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
+    if (rc)
+    {
+        requester.markFree(eid, instanceId);
+        std::cerr << "encode_pass_component_table_req failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        // Handle error scenario
+    }
+
+    rc = handler.registerRequest(
+        eid, instanceId, PLDM_FWUP, PLDM_PASS_COMPONENT_TABLE,
+        std::move(request),
+        std::move(std::bind_front(&DeviceUpdater::passCompTable, this)));
+    if (rc)
+    {
+        std::cerr << "Failed to send PassComponentTable request, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n ";
+        // Handle error scenario
+    }
+}
+
+void DeviceUpdater::passCompTable(mctp_eid_t eid, const pldm_msg* response,
+                                  size_t respMsgLen)
+{
+    if (response == nullptr || !respMsgLen)
+    {
+        // Handle error scenario
+        std::cerr << "No response received for PassComponentTable, EID="
+                  << unsigned(eid) << "\n";
+        return;
+    }
+
+    uint8_t completionCode = 0;
+    uint8_t compResponse = 0;
+    uint8_t compResponseCode = 0;
+
+    auto rc =
+        decode_pass_component_table_resp(response, respMsgLen, &completionCode,
+                                         &compResponse, &compResponseCode);
+    if (rc)
+    {
+        // Handle error scenario
+        std::cerr << "Decoding PassComponentTable response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return;
+    }
+    if (completionCode)
+    {
+        // Handle error scenario
+        std::cerr << "PassComponentTable response failed with error "
+                     "completion code, EID="
+                  << unsigned(eid) << ", CC=" << unsigned(completionCode)
+                  << "\n";
+        return;
+    }
+    // Handle ComponentResponseCode
+
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    if (componentIndex == applicableComponents.size() - 1)
+    {
+        componentIndex = 0;
+        pldmRequest = std::make_unique<sdeventplus::source::Defer>(
+            event, std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
+                             componentIndex));
+    }
+    else
+    {
+        componentIndex++;
+        pldmRequest = std::make_unique<sdeventplus::source::Defer>(
+            event, std::bind(&DeviceUpdater::sendPassCompTableRequest, this,
+                             componentIndex));
+    }
+}
+
+void DeviceUpdater::sendUpdateComponentRequest(size_t offset)
+{
+    pldmRequest.reset();
+
+    auto instanceId = requester.getInstanceId(eid);
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    const auto& comp = compImageInfos[applicableComponents[offset]];
+    // ComponentClassification
+    CompClassification compClassification = std::get<static_cast<size_t>(
+        ComponentImageInfoPos::CompClassificationPos)>(comp);
+    // ComponentIdentifier
+    CompIdentifier compIdentifier =
+        std::get<static_cast<size_t>(ComponentImageInfoPos::CompIdentifierPos)>(
+            comp);
+    // ComponentClassificationIndex
+    CompClassificationIndex compClassificationIndex{};
+    auto compKey = std::make_pair(compClassification, compIdentifier);
+    if (compInfo.contains(compKey))
+    {
+        auto search = compInfo.find(compKey);
+        compClassificationIndex = search->second;
+    }
+    else
+    {
+        // Handle error scenario
+    }
+
+    // UpdateOptionFlags
+    bitfield32_t updateOptionFlags;
+    updateOptionFlags.bits.bit0 = std::get<3>(comp)[0];
+    // ComponentVersion
+    const auto& compVersion = std::get<7>(comp);
+    variable_field compVerStrInfo{};
+    compVerStrInfo.ptr = reinterpret_cast<const uint8_t*>(compVersion.data());
+    compVerStrInfo.length = static_cast<uint8_t>(compVersion.size());
+
+    Request request(sizeof(pldm_msg_hdr) +
+                    sizeof(struct pldm_update_component_req) +
+                    compVerStrInfo.length);
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+
+    auto rc = encode_update_component_req(
+        instanceId, compClassification, compIdentifier, compClassificationIndex,
+        std::get<static_cast<size_t>(
+            ComponentImageInfoPos::CompComparisonStampPos)>(comp),
+        std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(comp),
+        updateOptionFlags, PLDM_STR_TYPE_ASCII, compVerStrInfo.length,
+        &compVerStrInfo, requestMsg,
+        sizeof(pldm_update_component_req) + compVerStrInfo.length);
+    if (rc)
+    {
+        requester.markFree(eid, instanceId);
+        std::cerr << "encode_update_component_req failed, EID=" << unsigned(eid)
+                  << ", RC=" << rc << "\n";
+        // Handle error scenario
+    }
+
+    rc = handler.registerRequest(
+        eid, instanceId, PLDM_FWUP, PLDM_UPDATE_COMPONENT, std::move(request),
+        std::move(std::bind_front(&DeviceUpdater::updateComponent, this)));
+    if (rc)
+    {
+        std::cerr << "Failed to send UpdateComponent request, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n ";
+        // Handle error scenario
+    }
+}
+
+void DeviceUpdater::updateComponent(mctp_eid_t eid, const pldm_msg* response,
+                                    size_t respMsgLen)
+{
+    if (response == nullptr || !respMsgLen)
+    {
+        // Handle error scenario
+        std::cerr << "No response received for updateComponent, EID="
+                  << unsigned(eid) << "\n";
+        return;
+    }
+
+    uint8_t completionCode = 0;
+    uint8_t compCompatibilityResp = 0;
+    uint8_t compCompatibilityRespCode = 0;
+    bitfield32_t updateOptionFlagsEnabled{};
+    uint16_t timeBeforeReqFWData = 0;
+
+    auto rc = decode_update_component_resp(
+        response, respMsgLen, &completionCode, &compCompatibilityResp,
+        &compCompatibilityRespCode, &updateOptionFlagsEnabled,
+        &timeBeforeReqFWData);
+    if (rc)
+    {
+        std::cerr << "Decoding UpdateComponent response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return;
+    }
+    if (completionCode)
+    {
+        std::cerr << "UpdateComponent response failed with error "
+                     "completion code, EID="
+                  << unsigned(eid) << ", CC=" << unsigned(completionCode)
+                  << "\n";
+        return;
+    }
+}
+
+Response DeviceUpdater::requestFwData(const pldm_msg* request,
+                                      size_t payloadLength)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
+    auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
+    auto rc = decode_request_firmware_data_req(request, payloadLength, &offset,
+                                               &length);
+    if (rc)
+    {
+        std::cerr << "Decoding RequestFirmwareData request failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        rc = encode_request_firmware_data_resp(
+            request->hdr.instance_id, PLDM_ERROR_INVALID_DATA, responseMsg,
+            sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding RequestFirmwareData response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    const auto& comp = compImageInfos[applicableComponents[componentIndex]];
+    auto compOffset = std::get<5>(comp);
+    auto compSize = std::get<6>(comp);
+    std::cerr << "offset = " << unsigned(offset)
+              << ", length = " << unsigned(length) << "\n";
+
+    if (length < PLDM_FWUP_BASELINE_TRANSFER_SIZE || length > maxTransferSize)
+    {
+        rc = encode_request_firmware_data_resp(
+            request->hdr.instance_id, PLDM_FWUP_INVALID_TRANSFER_LENGTH,
+            responseMsg, sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding RequestFirmwareData response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    if (offset + length > compSize + PLDM_FWUP_BASELINE_TRANSFER_SIZE)
+    {
+        rc = encode_request_firmware_data_resp(
+            request->hdr.instance_id, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg,
+            sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding RequestFirmwareData response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    size_t padBytes = 0;
+    if (offset + length > compSize)
+    {
+        padBytes = offset + length - compSize;
+    }
+
+    response.resize(sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
+    responseMsg = reinterpret_cast<pldm_msg*>(response.data());
+    package.seekg(compOffset + offset);
+    package.read(reinterpret_cast<char*>(response.data() +
+                                         sizeof(pldm_msg_hdr) +
+                                         sizeof(completionCode)),
+                 length - padBytes);
+    rc = encode_request_firmware_data_resp(request->hdr.instance_id,
+                                           completionCode, responseMsg,
+                                           sizeof(completionCode));
+    if (rc)
+    {
+        std::cerr << "Encoding RequestFirmwareData response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return response;
+    }
+
+    return response;
+}
+
+Response DeviceUpdater::transferComplete(const pldm_msg* request,
+                                         size_t payloadLength)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
+    auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
+
+    uint8_t transferResult = 0;
+    auto rc =
+        decode_transfer_complete_req(request, payloadLength, &transferResult);
+    if (rc)
+    {
+        std::cerr << "Decoding TransferComplete request failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        rc = encode_transfer_complete_resp(request->hdr.instance_id,
+                                           PLDM_ERROR_INVALID_DATA, responseMsg,
+                                           sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding TransferComplete response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    const auto& comp = compImageInfos[applicableComponents[componentIndex]];
+    const auto& compVersion = std::get<7>(comp);
+
+    if (transferResult == PLDM_FWUP_TRANSFER_SUCCESS)
+    {
+        std::cout << "Component Transfer complete, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion << "\n";
+    }
+    else
+    {
+        std::cerr << "Transfer of the component failed, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion
+                  << ", TRANSFER_RESULT=" << unsigned(transferResult) << "\n";
+    }
+
+    rc = encode_transfer_complete_resp(request->hdr.instance_id, completionCode,
+                                       responseMsg, sizeof(completionCode));
+    if (rc)
+    {
+        std::cerr << "Encoding TransferComplete response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return response;
+    }
+
+    return response;
+}
+
+Response DeviceUpdater::verifyComplete(const pldm_msg* request,
+                                       size_t payloadLength)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
+    auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
+
+    uint8_t verifyResult = 0;
+    auto rc = decode_verify_complete_req(request, payloadLength, &verifyResult);
+    if (rc)
+    {
+        std::cerr << "Decoding VerifyComplete request failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        rc = encode_verify_complete_resp(request->hdr.instance_id,
+                                         PLDM_ERROR_INVALID_DATA, responseMsg,
+                                         sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding VerifyComplete response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    const auto& comp = compImageInfos[applicableComponents[componentIndex]];
+    const auto& compVersion = std::get<7>(comp);
+
+    if (verifyResult == PLDM_FWUP_VERIFY_SUCCESS)
+    {
+        std::cout << "Component verification complete, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion << "\n";
+    }
+    else
+    {
+        std::cerr << "Component verification failed, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion
+                  << ", VERIFY_RESULT=" << unsigned(verifyResult) << "\n";
+    }
+
+    rc = encode_verify_complete_resp(request->hdr.instance_id, completionCode,
+                                     responseMsg, sizeof(completionCode));
+    if (rc)
+    {
+        std::cerr << "Encoding VerifyComplete response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return response;
+    }
+
+    return response;
+}
+
+Response DeviceUpdater::applyComplete(const pldm_msg* request,
+                                      size_t payloadLength)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    Response response(sizeof(pldm_msg_hdr) + sizeof(completionCode), 0);
+    auto responseMsg = reinterpret_cast<pldm_msg*>(response.data());
+
+    uint8_t applyResult = 0;
+    bitfield16_t compActivationModification{};
+    auto rc = decode_apply_complete_req(request, payloadLength, &applyResult,
+                                        &compActivationModification);
+    if (rc)
+    {
+        std::cerr << "Decoding ApplyComplete request failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        rc = encode_apply_complete_resp(request->hdr.instance_id,
+                                        PLDM_ERROR_INVALID_DATA, responseMsg,
+                                        sizeof(completionCode));
+        if (rc)
+        {
+            std::cerr << "Encoding ApplyComplete response failed, EID="
+                      << unsigned(eid) << ", RC=" << rc << "\n";
+        }
+        return response;
+    }
+
+    const auto& applicableComponents =
+        std::get<ApplicableComponents>(fwDeviceIDRecord);
+    const auto& comp = compImageInfos[applicableComponents[componentIndex]];
+    const auto& compVersion = std::get<7>(comp);
+
+    if (applyResult == PLDM_FWUP_APPLY_SUCCESS ||
+        applyResult == PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD)
+    {
+        std::cout << "Component apply complete, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion << "\n";
+    }
+    else
+    {
+        std::cerr << "Component apply failed, EID=" << unsigned(eid)
+                  << ", COMPONENT_VERSION=" << compVersion
+                  << ", APPLY_RESULT=" << unsigned(applyResult) << "\n";
+    }
+
+    rc = encode_apply_complete_resp(request->hdr.instance_id, completionCode,
+                                    responseMsg, sizeof(completionCode));
+    if (rc)
+    {
+        std::cerr << "Encoding ApplyComplete response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return response;
+    }
+
+    if (componentIndex == applicableComponents.size() - 1)
+    {
+        componentIndex = 0;
+        pldmRequest = std::make_unique<sdeventplus::source::Defer>(
+            event,
+            std::bind(&DeviceUpdater::sendActivateFirmwareRequest, this));
+    }
+    else
+    {
+        componentIndex++;
+        pldmRequest = std::make_unique<sdeventplus::source::Defer>(
+            event, std::bind(&DeviceUpdater::sendUpdateComponentRequest, this,
+                             componentIndex));
+    }
+
+    return response;
+}
+
+void DeviceUpdater::sendActivateFirmwareRequest()
+{
+    pldmRequest.reset();
+    auto instanceId = requester.getInstanceId(eid);
+    Request request(sizeof(pldm_msg_hdr) +
+                    sizeof(struct pldm_activate_firmware_req));
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+
+    auto rc = encode_activate_firmware_req(
+        instanceId, PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS, requestMsg,
+        sizeof(pldm_activate_firmware_req));
+    if (rc)
+    {
+        requester.markFree(eid, instanceId);
+        std::cerr << "encode_activate_firmware_req failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+    }
+
+    rc = handler.registerRequest(
+        eid, instanceId, PLDM_FWUP, PLDM_ACTIVATE_FIRMWARE, std::move(request),
+        std::move(std::bind_front(&DeviceUpdater::activateFirmware, this)));
+    if (rc)
+    {
+        std::cerr << "Failed to send ActivateFirmware request, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n ";
+    }
+}
+
+void DeviceUpdater::activateFirmware(mctp_eid_t eid, const pldm_msg* response,
+                                     size_t respMsgLen)
+{
+    if (response == nullptr || !respMsgLen)
+    {
+        // Handle error scenario
+        std::cerr << "No response received for ActivateFirmware, EID="
+                  << unsigned(eid) << "\n";
+        return;
+    }
+
+    uint8_t completionCode = 0;
+    uint16_t estimatedTimeForActivation = 0;
+
+    auto rc = decode_activate_firmware_resp(
+        response, respMsgLen, &completionCode, &estimatedTimeForActivation);
+    if (rc)
+    {
+        // Handle error scenario
+        std::cerr << "Decoding ActivateFirmware response failed, EID="
+                  << unsigned(eid) << ", RC=" << rc << "\n";
+        return;
+    }
+    if (completionCode)
+    {
+        // Handle error scenario
+        std::cerr << "ActivateFirmware response failed with error "
+                     "completion code, EID="
+                  << unsigned(eid) << ", CC=" << unsigned(completionCode)
+                  << "\n";
+        return;
+    }
+}
+
+} // namespace fw_update
+
+} // namespace pldm
\ No newline at end of file