| // Copyright 2024 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "hoth_update.hpp" |
| |
| #include <phosphor-logging/log.hpp> |
| #include <sdbusplus/message.hpp> |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <cstring> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| using phosphor::logging::entry; |
| using phosphor::logging::log; |
| |
| using level = phosphor::logging::level; |
| using SdBusError = sdbusplus::exception::SdBusError; |
| |
| namespace ipmi_hoth |
| { |
| |
| void updateBlobState(uint16_t& state, |
| internal::DbusUpdate::FirmwareUpdateStatus st) |
| { |
| state &= ~(blobs::StateFlags::commit_error | blobs::StateFlags::committing | |
| blobs::StateFlags::committed); |
| switch (st) |
| { |
| case internal::DbusUpdate::FirmwareUpdateStatus::None: |
| break; |
| case internal::DbusUpdate::FirmwareUpdateStatus::InProgress: |
| state |= blobs::StateFlags::committing; |
| break; |
| case internal::DbusUpdate::FirmwareUpdateStatus::Error: |
| state |= blobs::StateFlags::commit_error; |
| break; |
| case internal::DbusUpdate::FirmwareUpdateStatus::Done: |
| state |= blobs::StateFlags::committed; |
| break; |
| } |
| } |
| |
| bool HothUpdateBlobHandler::stat(const std::string& path, blobs::BlobMeta* meta) |
| { |
| std::optional<uint16_t> sess = getOnlySession(pathToHothId(path)); |
| if (!sess) |
| { |
| return false; |
| } |
| |
| /* Call session stat with the session ID of the only session */ |
| return stat(*sess, meta); |
| } |
| |
| bool HothUpdateBlobHandler::commit(uint16_t session, |
| const std::vector<uint8_t>& data) |
| { |
| if (!data.empty()) |
| { |
| log<level::ERR>("Unexpected data provided to commit call"); |
| return false; |
| } |
| |
| HothBlob* sess = getSession(session); |
| if (!sess) |
| { |
| return false; |
| } |
| |
| // If commit is called multiple times, return the same result as last time |
| if (sess->state & |
| (blobs::StateFlags::committing | blobs::StateFlags::committed)) |
| { |
| return true; |
| } |
| |
| updateBlobState(sess->state, |
| internal::DbusUpdate::FirmwareUpdateStatus::InProgress); |
| sess->outstanding = dbus_->UpdateFirmware( |
| sess->hothId, sess->buffer, |
| [sess](internal::DbusUpdate::FirmwareUpdateStatus rsp) { |
| auto outstanding = std::move(sess->outstanding); |
| updateBlobState(sess->state, rsp); |
| }); |
| return true; |
| } |
| |
| bool HothUpdateBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta) |
| { |
| HothBlob* sess = getSession(session); |
| if (!sess) |
| { |
| // Return false since blobs::BlobMeta was not updated |
| return false; |
| } |
| |
| // We only want to start a new status check if we don't have a pending job |
| // and we hoth't receivied a completion state (error / done). |
| if (!sess->outstanding && (sess->state & blobs::StateFlags::committing)) |
| { |
| sess->outstanding = dbus_->GetFirmwareUpdateStatus( |
| sess->hothId, |
| [sess](internal::DbusUpdate::FirmwareUpdateStatus rsp) { |
| auto outstanding = std::move(sess->outstanding); |
| updateBlobState(sess->state, rsp); |
| }); |
| } |
| |
| meta->size = sess->buffer.size(); |
| meta->blobState = sess->state; |
| // Return true since blobs::BlobMeta was updated |
| return true; |
| } |
| |
| } // namespace ipmi_hoth |