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
diff --git a/fw-update/device_updater.hpp b/fw-update/device_updater.hpp
new file mode 100644
index 0000000..95f8adf
--- /dev/null
+++ b/fw-update/device_updater.hpp
@@ -0,0 +1,230 @@
+#pragma once
+
+#include "common/types.hpp"
+#include "requester/handler.hpp"
+#include "requester/request.hpp"
+
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/source/event.hpp>
+
+#include <fstream>
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+class UpdateManager;
+
+/** @class DeviceUpdater
+ *
+ *  DeviceUpdater orchestrates the firmware update of the firmware device and
+ *  updates the UpdateManager about the status once it is complete.
+ */
+class DeviceUpdater
+{
+  public:
+    DeviceUpdater() = delete;
+    DeviceUpdater(const DeviceUpdater&) = delete;
+    DeviceUpdater(DeviceUpdater&&) = default;
+    DeviceUpdater& operator=(const DeviceUpdater&) = delete;
+    DeviceUpdater& operator=(DeviceUpdater&&) = default;
+    ~DeviceUpdater() = default;
+
+    /** @brief Constructor
+     *
+     *  @param[in] eid - Endpoint ID of the firmware device
+     *  @param[in] event - PLDM daemon's main event loop
+     *  @param[in] requester - Instance ID manager for PLDM requests
+     *  @param[in] handler - PLDM request handler
+     *  @param[in] package - File stream for firmware update package
+     *  @param[in] fwDeviceIDRecord - FirmwareDeviceIDRecord in the fw update
+     *                                package that matches this firmware device
+     *  @param[in] compImageInfos - Component image information for all the
+     *                              components in the fw update package
+     *  @param[in] compInfo - Component info for the components in this FD
+     *                        derived from GetFirmwareParameters response
+     *  @param[in] maxTransferSize - Maximum size in bytes of the variable
+     *                               payload allowed to be requested by the FD
+     *  @param[in] updateManager - To update the status of fw update of the
+     *                             device
+     */
+    explicit DeviceUpdater(
+        mctp_eid_t eid, sdeventplus::Event& event,
+        pldm::dbus_api::Requester& requester,
+        pldm::requester::Handler<pldm::requester::Request>& handler,
+        std::ifstream& package, const FirmwareDeviceIDRecord& fwDeviceIDRecord,
+        const ComponentImageInfos& compImageInfos,
+        const ComponentInfo& compInfo, uint32_t maxTransferSize,
+        UpdateManager* updateManager) :
+        eid(eid),
+        event(event), requester(requester), handler(handler), package(package),
+        fwDeviceIDRecord(fwDeviceIDRecord), compImageInfos(compImageInfos),
+        compInfo(compInfo), maxTransferSize(maxTransferSize),
+        updateManager(updateManager)
+    {}
+
+    /** @brief Start the firmware update flow for the FD
+     *
+     *  To start the update flow RequestUpdate command is sent to the FD.
+     *
+     */
+    void startFwUpdateFlow();
+
+    /** @brief Handler for RequestUpdate command response
+     *
+     *  The response of the RequestUpdate is processed and if the response
+     *  is success, send PassComponentTable request to FD.
+     *
+     *  @param[in] eid - Remote MCTP endpoint
+     *  @param[in] response - PLDM response message
+     *  @param[in] respMsgLen - Response message length
+     */
+    void requestUpdate(mctp_eid_t eid, const pldm_msg* response,
+                       size_t respMsgLen);
+
+    /** @brief Handler for PassComponentTable command response
+     *
+     *  The response of the PassComponentTable is processed. If the response
+     *  indicates component can be updated, continue with either a) or b).
+     *
+     *  a. Send PassComponentTable request for the next component if
+     *     applicable
+     *  b. UpdateComponent command to request updating a specific
+     *     firmware component
+     *
+     *  If the response indicates component may be updateable, continue
+     *  based on the policy in DeviceUpdateOptionFlags.
+     *
+     *  @param[in] eid - Remote MCTP endpoint
+     *  @param[in] response - PLDM response message
+     *  @param[in] respMsgLen - Response message length
+     */
+    void passCompTable(mctp_eid_t eid, const pldm_msg* response,
+                       size_t respMsgLen);
+
+    /** @brief Handler for UpdateComponent command response
+     *
+     *  The response of the UpdateComponent is processed and will wait for
+     *  FD to request the firmware data.
+     *
+     *  @param[in] eid - Remote MCTP endpoint
+     *  @param[in] response - PLDM response message
+     *  @param[in] respMsgLen - Response message length
+     */
+    void updateComponent(mctp_eid_t eid, const pldm_msg* response,
+                         size_t respMsgLen);
+
+    /** @brief Handler for RequestFirmwareData request
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @return Response - PLDM Response message
+     */
+    Response requestFwData(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for TransferComplete request
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @return Response - PLDM Response message
+     */
+    Response transferComplete(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for VerifyComplete request
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @return Response - PLDM Response message
+     */
+    Response verifyComplete(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for ApplyComplete request
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @return Response - PLDM Response message
+     */
+    Response applyComplete(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for ActivateFirmware command response
+     *
+     *  The response of the ActivateFirmware is processed and will update the
+     *  UpdateManager with the completion of the firmware update.
+     *
+     *  @param[in] eid - Remote MCTP endpoint
+     *  @param[in] response - PLDM response message
+     *  @param[in] respMsgLen - Response message length
+     */
+    void activateFirmware(mctp_eid_t eid, const pldm_msg* response,
+                          size_t respMsgLen);
+
+  private:
+    /** @brief Send PassComponentTable command request
+     *
+     *  @param[in] compOffset - component offset in compImageInfos
+     */
+    void sendPassCompTableRequest(size_t offset);
+
+    /** @brief Send UpdateComponent command request
+     *
+     *  @param[in] compOffset - component offset in compImageInfos
+     */
+    void sendUpdateComponentRequest(size_t offset);
+
+    /** @brief Send ActivateFirmware command request */
+    void sendActivateFirmwareRequest();
+
+    /** @brief Endpoint ID of the firmware device */
+    mctp_eid_t eid;
+
+    /** @brief PLDM daemon's main event loop */
+    sdeventplus::Event& event;
+
+    /** @brief Instance ID manager for PLDM requests */
+    pldm::dbus_api::Requester& requester;
+
+    /** @brief PLDM request handler */
+    pldm::requester::Handler<pldm::requester::Request>& handler;
+
+    /** @brief File stream for firmware update package */
+    std::ifstream& package;
+
+    /** @brief FirmwareDeviceIDRecord in the fw update package that matches this
+     *         firmware device
+     */
+    const FirmwareDeviceIDRecord& fwDeviceIDRecord;
+
+    /** @brief Component image information for all the components in the fw
+     *         update package
+     */
+    const ComponentImageInfos& compImageInfos;
+
+    /** @brief Component info for the components in this FD derived from
+     *         GetFirmwareParameters response
+     */
+    const ComponentInfo& compInfo;
+
+    /** @brief Maximum size in bytes of the variable payload to be requested by
+     *         the FD via RequestFirmwareData command
+     */
+    uint32_t maxTransferSize;
+
+    /** @brief To update the status of fw update of the FD */
+    UpdateManager* updateManager;
+
+    /** @brief Component index is used to track the current component being
+     *         updated if multiple components are applicable for the FD.
+     *         It is also used to keep track of the next component in
+     *         PassComponentTable
+     */
+    size_t componentIndex = 0;
+
+    /** @brief To send a PLDM request after the current command handling */
+    std::unique_ptr<sdeventplus::source::Defer> pldmRequest;
+};
+
+} // namespace fw_update
+
+} // namespace pldm
\ No newline at end of file
diff --git a/fw-update/test/device_updater_test.cpp b/fw-update/test/device_updater_test.cpp
new file mode 100644
index 0000000..24f85e2
--- /dev/null
+++ b/fw-update/test/device_updater_test.cpp
@@ -0,0 +1,162 @@
+#include "libpldm/firmware_update.h"
+
+#include "common/utils.hpp"
+#include "fw-update/device_updater.hpp"
+#include "fw-update/package_parser.hpp"
+#include "pldmd/dbus_impl_requester.hpp"
+#include "requester/handler.hpp"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm;
+using namespace std::chrono;
+using namespace pldm::fw_update;
+
+class DeviceUpdaterTest : public testing::Test
+{
+  protected:
+    DeviceUpdaterTest() :
+        event(sdeventplus::Event::get_default()),
+        requester(pldm::utils::DBusHandler::getBus(),
+                  "/xyz/openbmc_project/pldm"),
+        reqHandler(fd, event, requester, false, seconds(1), 2,
+                   milliseconds(100)),
+        package("./test_pkg", std::ios::binary | std::ios::in | std::ios::ate)
+    {
+        fwDeviceIDRecord = {
+            1,
+            {0x00},
+            "VersionString2",
+            {{PLDM_FWUP_UUID,
+              std::vector<uint8_t>{0x16, 0x20, 0x23, 0xC9, 0x3E, 0xC5, 0x41,
+                                   0x15, 0x95, 0xF4, 0x48, 0x70, 0x1D, 0x49,
+                                   0xD6, 0x75}}},
+            {}};
+        compImageInfos = {
+            {10, 100, 0xFFFFFFFF, 0, 0, 139, 1024, "VersionString3"}};
+        compInfo = {{std::make_pair(10, 100), 1}};
+    }
+
+    int fd = -1;
+    sdeventplus::Event event;
+    pldm::dbus_api::Requester requester;
+    requester::Handler<requester::Request> reqHandler;
+    std::ifstream package;
+    FirmwareDeviceIDRecord fwDeviceIDRecord;
+    ComponentImageInfos compImageInfos;
+    ComponentInfo compInfo;
+};
+
+TEST_F(DeviceUpdaterTest, validatePackage)
+{
+    constexpr uintmax_t testPkgSize = 1163;
+    uintmax_t packageSize = package.tellg();
+    EXPECT_EQ(packageSize, testPkgSize);
+
+    package.seekg(0);
+    std::vector<uint8_t> packageHeader(sizeof(pldm_package_header_information));
+    package.read(reinterpret_cast<char*>(packageHeader.data()),
+                 sizeof(pldm_package_header_information));
+
+    auto pkgHeaderInfo =
+        reinterpret_cast<const pldm_package_header_information*>(
+            packageHeader.data());
+    auto pkgHeaderInfoSize = sizeof(pldm_package_header_information) +
+                             pkgHeaderInfo->package_version_string_length;
+    packageHeader.clear();
+    packageHeader.resize(pkgHeaderInfoSize);
+    package.seekg(0);
+    package.read(reinterpret_cast<char*>(packageHeader.data()),
+                 pkgHeaderInfoSize);
+
+    auto parser = parsePkgHeader(packageHeader);
+    EXPECT_NE(parser, nullptr);
+
+    package.seekg(0);
+    packageHeader.resize(parser->pkgHeaderSize);
+    package.read(reinterpret_cast<char*>(packageHeader.data()),
+                 parser->pkgHeaderSize);
+
+    parser->parse(packageHeader, packageSize);
+    const auto& fwDeviceIDRecords = parser->getFwDeviceIDRecords();
+    const auto& testPkgCompImageInfos = parser->getComponentImageInfos();
+
+    EXPECT_EQ(fwDeviceIDRecords.size(), 1);
+    EXPECT_EQ(compImageInfos.size(), 1);
+    EXPECT_EQ(fwDeviceIDRecords[0], fwDeviceIDRecord);
+    EXPECT_EQ(testPkgCompImageInfos, compImageInfos);
+}
+
+TEST_F(DeviceUpdaterTest, ReadPackage512B)
+{
+    DeviceUpdater deviceUpdater(0, event, requester, reqHandler, package,
+                                fwDeviceIDRecord, compImageInfos, compInfo, 512,
+                                nullptr);
+
+    constexpr std::array<uint8_t, sizeof(pldm_msg_hdr) +
+                                      sizeof(pldm_request_firmware_data_req)>
+        reqFwDataReq{0x8A, 0x05, 0x15, 0x00, 0x00, 0x00,
+                     0x00, 0x00, 0x02, 0x00, 0x00};
+    constexpr uint8_t instanceId = 0x0A;
+    constexpr uint8_t completionCode = PLDM_SUCCESS;
+    constexpr uint32_t length = 512;
+    auto requestMsg = reinterpret_cast<const pldm_msg*>(reqFwDataReq.data());
+    auto response = deviceUpdater.requestFwData(
+        requestMsg, sizeof(pldm_request_firmware_data_req));
+
+    EXPECT_EQ(response.size(),
+              sizeof(pldm_msg_hdr) + sizeof(completionCode) + length);
+    auto responeMsg = reinterpret_cast<const pldm_msg*>(response.data());
+    EXPECT_EQ(responeMsg->hdr.request, PLDM_RESPONSE);
+    EXPECT_EQ(responeMsg->hdr.instance_id, instanceId);
+    EXPECT_EQ(responeMsg->hdr.type, PLDM_FWUP);
+    EXPECT_EQ(responeMsg->hdr.command, PLDM_REQUEST_FIRMWARE_DATA);
+    EXPECT_EQ(response[sizeof(pldm_msg_hdr)], completionCode);
+
+    const std::vector<uint8_t> compFirst512B{
+        0x0A, 0x05, 0x15, 0x00, 0x48, 0xD2, 0x1E, 0x80, 0x2E, 0x77, 0x71, 0x2C,
+        0x8E, 0xE3, 0x1F, 0x6F, 0x30, 0x76, 0x65, 0x08, 0xB8, 0x1B, 0x4B, 0x03,
+        0x7E, 0x96, 0xD9, 0x2A, 0x36, 0x3A, 0xA2, 0xEE, 0x8A, 0x30, 0x21, 0x33,
+        0xFC, 0x27, 0xE7, 0x3E, 0x56, 0x79, 0x0E, 0xBD, 0xED, 0x44, 0x96, 0x2F,
+        0x84, 0xB5, 0xED, 0x19, 0x3A, 0x5E, 0x62, 0x2A, 0x6E, 0x41, 0x7E, 0xDC,
+        0x2E, 0xBB, 0x87, 0x41, 0x7F, 0xCE, 0xF0, 0xD7, 0xE4, 0x0F, 0x95, 0x33,
+        0x3B, 0xF9, 0x04, 0xF8, 0x1A, 0x92, 0x54, 0xFD, 0x33, 0xBA, 0xCD, 0xA6,
+        0x08, 0x0D, 0x32, 0x2C, 0xEB, 0x75, 0xDC, 0xEA, 0xBA, 0x30, 0x94, 0x78,
+        0x8C, 0x61, 0x58, 0xD0, 0x59, 0xF3, 0x29, 0x6D, 0x67, 0xD3, 0x26, 0x08,
+        0x25, 0x1E, 0x69, 0xBB, 0x28, 0xB0, 0x61, 0xFB, 0x96, 0xA3, 0x8C, 0xBF,
+        0x01, 0x94, 0xEB, 0x3A, 0x63, 0x6F, 0xC8, 0x0F, 0x42, 0x7F, 0xEB, 0x3D,
+        0xA7, 0x8B, 0xE5, 0xD2, 0xFB, 0xB8, 0xD3, 0x15, 0xAA, 0xDF, 0x86, 0xAB,
+        0x6E, 0x29, 0xB3, 0x12, 0x96, 0xB7, 0x86, 0xDA, 0xF9, 0xD7, 0x70, 0xAD,
+        0xB6, 0x1A, 0x29, 0xB1, 0xA4, 0x2B, 0x6F, 0x63, 0xEE, 0x05, 0x9F, 0x35,
+        0x49, 0xA1, 0xAB, 0xA2, 0x6F, 0x7C, 0xFC, 0x23, 0x09, 0x55, 0xED, 0xF7,
+        0x35, 0xD8, 0x2F, 0x8F, 0xD2, 0xBD, 0x77, 0xED, 0x0C, 0x7A, 0xE9, 0xD3,
+        0xF7, 0x90, 0xA7, 0x45, 0x97, 0xAA, 0x3A, 0x79, 0xC4, 0xF8, 0xD2, 0xFE,
+        0xFB, 0xB3, 0x25, 0x86, 0x98, 0x6B, 0x98, 0x10, 0x15, 0xB3, 0xDD, 0x43,
+        0x0B, 0x20, 0x5F, 0xE4, 0x62, 0xC8, 0xA1, 0x3E, 0x9C, 0xF3, 0xD8, 0xEA,
+        0x15, 0xA1, 0x24, 0x94, 0x1C, 0xF5, 0xB4, 0x86, 0x04, 0x30, 0x2C, 0x84,
+        0xB6, 0x29, 0xF6, 0x9D, 0x76, 0x6E, 0xD4, 0x0C, 0x1C, 0xBD, 0xF9, 0x95,
+        0x7E, 0xAF, 0x62, 0x80, 0x14, 0xE6, 0x1C, 0x43, 0x51, 0x5C, 0xCA, 0x50,
+        0xE1, 0x73, 0x3D, 0x75, 0x66, 0x52, 0x9E, 0xB6, 0x15, 0x7E, 0xF7, 0xE5,
+        0xE2, 0xAF, 0x54, 0x75, 0x82, 0x3D, 0x55, 0xC7, 0x59, 0xD7, 0xBD, 0x8C,
+        0x4B, 0x74, 0xD1, 0x3F, 0xA8, 0x1B, 0x0A, 0xF0, 0x5A, 0x32, 0x2B, 0xA7,
+        0xA4, 0xBE, 0x38, 0x18, 0xAE, 0x69, 0xDC, 0x54, 0x7C, 0x60, 0xEF, 0x4F,
+        0x0F, 0x7F, 0x5A, 0xA6, 0xC8, 0x3E, 0x59, 0xFD, 0xF5, 0x98, 0x26, 0x71,
+        0xD0, 0xEF, 0x54, 0x47, 0x38, 0x1F, 0x18, 0x9D, 0x37, 0x9D, 0xF0, 0xCD,
+        0x00, 0x73, 0x30, 0xD4, 0xB7, 0xDA, 0x2D, 0x36, 0xA1, 0xA9, 0xAD, 0x4F,
+        0x9F, 0x17, 0xA5, 0xA1, 0x62, 0x18, 0x21, 0xDD, 0x0E, 0xB6, 0x72, 0xDE,
+        0x17, 0xF0, 0x71, 0x94, 0xA9, 0x67, 0xB4, 0x75, 0xDB, 0x64, 0xF0, 0x6E,
+        0x3D, 0x4E, 0x29, 0x45, 0x42, 0xC3, 0xDA, 0x1F, 0x9E, 0x31, 0x4D, 0x1B,
+        0xA7, 0x9D, 0x07, 0xD9, 0x10, 0x75, 0x27, 0x92, 0x16, 0x35, 0xF5, 0x51,
+        0x3E, 0x14, 0x00, 0xB4, 0xBD, 0x21, 0xAF, 0x90, 0xC5, 0xE5, 0xEE, 0xD0,
+        0xB3, 0x7F, 0x61, 0xA5, 0x1B, 0x91, 0xD5, 0x66, 0x08, 0xB5, 0x16, 0x25,
+        0xC2, 0x16, 0x53, 0xDC, 0xB5, 0xF1, 0xDD, 0xCF, 0x28, 0xDD, 0x57, 0x90,
+        0x66, 0x33, 0x7B, 0x75, 0xF4, 0x8A, 0x19, 0xAC, 0x1F, 0x44, 0xC2, 0xF6,
+        0x21, 0x07, 0xE9, 0xCC, 0xDD, 0xCF, 0x4A, 0x34, 0xA1, 0x24, 0x82, 0xF8,
+        0xA1, 0x1D, 0x06, 0x90, 0x4B, 0x97, 0xB8, 0x10, 0xF2, 0x6A, 0x55, 0x30,
+        0xD9, 0x4F, 0x94, 0xE7, 0x7C, 0xBB, 0x73, 0xA3, 0x5F, 0xC6, 0xF1, 0xDB,
+        0x84, 0x3D, 0x29, 0x72, 0xD1, 0xAD, 0x2D, 0x77, 0x3F, 0x36, 0x24, 0x0F,
+        0xC4, 0x12, 0xD7, 0x3C, 0x65, 0x6C, 0xE1, 0x5A, 0x32, 0xAA, 0x0B, 0xA3,
+        0xA2, 0x72, 0x33, 0x00, 0x3C, 0x7E, 0x28, 0x36, 0x10, 0x90, 0x38, 0xFB};
+    EXPECT_EQ(response, compFirst512B);
+}
diff --git a/fw-update/test/meson.build b/fw-update/test/meson.build
index 24dc068..2a66c93 100644
--- a/fw-update/test/meson.build
+++ b/fw-update/test/meson.build
@@ -2,6 +2,7 @@
           sources: [
             '../inventory_manager.cpp',
             '../package_parser.cpp',
+            '../device_updater.cpp',
             '../../common/utils.cpp',
             '../../pldmd/dbus_impl_requester.cpp',
             '../../pldmd/instance_id.cpp'])
@@ -9,6 +10,7 @@
 tests = [
   'inventory_manager_test',
   'package_parser_test',
+  'device_updater_test'
 ]
 
 foreach t : tests
diff --git a/fw-update/test/test_pkg b/fw-update/test/test_pkg
new file mode 100644
index 0000000..ccf9568
--- /dev/null
+++ b/fw-update/test/test_pkg
Binary files differ
diff --git a/meson.build b/meson.build
index a5b04ae..a8ed7e5 100644
--- a/meson.build
+++ b/meson.build
@@ -60,6 +60,7 @@
 if get_option('libpldm-only').disabled()
   conf_data.set_quoted('HOST_EID_PATH', join_paths(package_datadir, 'host_eid'))
 endif
+conf_data.set('MAXIMUM_TRANSFER_SIZE', get_option('maximum-transfer-size'))
 configure_file(output: 'config.h',
   configuration: conf_data
 )
@@ -196,6 +197,7 @@
   'pldmd/dbus_impl_pdr.cpp',
   'fw-update/inventory_manager.cpp',
   'fw-update/package_parser.cpp',
+  'fw-update/device_updater.cpp',
   implicit_include_directories: false,
   dependencies: deps,
   install: true,
diff --git a/meson_options.txt b/meson_options.txt
index a535fee..0cb99df 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -25,3 +25,5 @@
 option('terminus-id', type:'integer', min:0, max: 255, description: 'The terminus id value of the device that is running this pldm stack', value:1)
 option('terminus-handle',type:'integer',min:0, max:65535, description: 'The terminus handle value of the device that is running this pldm stack', value:1)
 
+# Firmware update configuration parameters
+option('maximum-transfer-size', type: 'integer', min: 16, max: 4294967295, description: 'Maximum size in bytes of the variable payload allowed to be requested by the FD, via RequestFirmwareData command', value: 4096)