1 #pragma once 2 3 #include "config.h" 4 5 #include "data_handler.hpp" 6 #include "image_handler.hpp" 7 #include "status.hpp" 8 #include "util.hpp" 9 10 #include <blobs-ipmid/blobs.hpp> 11 12 #include <algorithm> 13 #include <cstdint> 14 #include <map> 15 #include <memory> 16 #include <string> 17 #include <unordered_map> 18 #include <vector> 19 20 namespace ipmi_flash 21 { 22 23 /** 24 * Given a firmware name, provide a set of triggerable action interfaces 25 * associated with that firmware type. 26 */ 27 struct ActionPack 28 { 29 /** The name of the action pack, something like image, or tarball, or bios. 30 * The firmware blob id is parsed to pull the "filename" portion from the 31 * path, and matched against the key to a map of these. 32 */ 33 std::unique_ptr<TriggerableActionInterface> preparation; 34 std::unique_ptr<TriggerableActionInterface> verification; 35 std::unique_ptr<TriggerableActionInterface> update; 36 }; 37 38 using ActionMap = 39 std::unordered_map<std::string, std::unique_ptr<ipmi_flash::ActionPack>>; 40 41 /** 42 * Representation of a session, includes how to read/write data. 43 */ 44 struct Session 45 { 46 /** 47 * Built a session object. 48 * 49 * @param[in] the active path to which this corresponds. 50 */ 51 explicit Session(const std::string& path) : 52 dataHandler(nullptr), imageHandler(nullptr), flags(0), activePath(path) 53 {} 54 55 /** 56 * Pointer to the correct Data handler interface. (nullptr on BT (or KCS)) 57 */ 58 DataInterface* dataHandler; 59 60 /** 61 * Pointer to the correct image handler interface. (nullptr on hash 62 * blob_id) 63 */ 64 ipmi_flash::ImageHandlerInterface* imageHandler; 65 66 /** The flags used to open the session. */ 67 std::uint16_t flags; 68 69 /** The active path. */ 70 std::string activePath; 71 }; 72 73 /** 74 * Register only one firmware blob handler that will manage all sessions. 75 */ 76 class FirmwareBlobHandler : public blobs::GenericBlobInterface 77 { 78 public: 79 /** The state of the firmware update process. */ 80 enum class UpdateState 81 { 82 /** The initial state. */ 83 notYetStarted = 0, 84 /** The BMC is expecting to receive bytes. */ 85 uploadInProgress, 86 /** The BMC is ready for verification or more bytes. */ 87 verificationPending, 88 /** The verification process has started, no more writes allowed. */ 89 verificationStarted, 90 /** The verification process has completed. */ 91 verificationCompleted, 92 /** The update process is pending. */ 93 updatePending, 94 /** The update process has started. */ 95 updateStarted, 96 /** The update has completed (optional state to reach) */ 97 updateCompleted, 98 }; 99 100 /** 101 * Create a FirmwareBlobHandler. 102 * 103 * @param[in] firmwares - list of firmware blob_ids to support. 104 * @param[in] transports - list of transports to support. 105 * @param[in] verification - pointer to object for triggering verification 106 * @param[in] update - point to object for triggering the update 107 */ 108 static std::unique_ptr<blobs::GenericBlobInterface> 109 CreateFirmwareBlobHandler(std::vector<HandlerPack>&& firmwares, 110 std::vector<DataHandlerPack>&& transports, 111 ActionMap&& actionPacks); 112 113 /** 114 * Create a FirmwareBlobHandler. 115 * 116 * @param[in] firmwares - list of firmware types and their handlers 117 * @param[in] blobs - list of blobs_ids to support 118 * @param[in] transports - list of transport types and their handlers 119 * @param[in] verification - pointer to object for triggering verification 120 * @param[in] update - point to object for triggering the update 121 */ 122 FirmwareBlobHandler(std::vector<HandlerPack>&& firmwares, 123 const std::vector<std::string>& blobs, 124 std::vector<DataHandlerPack>&& transports, 125 ActionMap&& actionPacks) : 126 handlers(std::move(firmwares)), 127 blobIDs(blobs), transports(std::move(transports)), 128 activeImage(activeImageBlobId), activeHash(activeHashBlobId), 129 verifyImage(verifyBlobId), updateImage(updateBlobId), lookup(), 130 state(UpdateState::notYetStarted), actionPacks(std::move(actionPacks)) 131 {} 132 ~FirmwareBlobHandler() = default; 133 FirmwareBlobHandler(const FirmwareBlobHandler&) = delete; 134 FirmwareBlobHandler& operator=(const FirmwareBlobHandler&) = delete; 135 FirmwareBlobHandler(FirmwareBlobHandler&&) = default; 136 FirmwareBlobHandler& operator=(FirmwareBlobHandler&&) = default; 137 138 bool canHandleBlob(const std::string& path) override; 139 std::vector<std::string> getBlobIds() override; 140 bool deleteBlob(const std::string& path) override; 141 bool stat(const std::string& path, blobs::BlobMeta* meta) override; 142 bool open(uint16_t session, uint16_t flags, 143 const std::string& path) override; 144 std::vector<uint8_t> read(uint16_t session, uint32_t offset, 145 uint32_t requestedSize) override; 146 bool write(uint16_t session, uint32_t offset, 147 const std::vector<uint8_t>& data) override; 148 bool writeMeta(uint16_t session, uint32_t offset, 149 const std::vector<uint8_t>& data) override; 150 bool commit(uint16_t session, const std::vector<uint8_t>& data) override; 151 bool close(uint16_t session) override; 152 bool stat(uint16_t session, blobs::BlobMeta* meta) override; 153 bool expire(uint16_t session) override; 154 155 void abortProcess(); 156 157 void abortVerification(); 158 bool triggerVerification(); 159 void abortUpdate(); 160 bool triggerUpdate(); 161 162 /** Allow grabbing the current state. */ 163 UpdateState getCurrentState() const 164 { 165 return state; 166 }; 167 168 /** Provide for any state change triggers in convenience handler. */ 169 void changeState(UpdateState next); 170 171 private: 172 /** 173 * Given the current session type, grab the ActionPack (likely will be 174 * worked into the Session for lookup). 175 */ 176 ActionPack* getActionPack() 177 { 178 if (openedFirmwareType.empty()) 179 { 180 /* No firmware type has been opened, but we're triggering 181 * verification, or preparing. This can happen if they open the hash 182 * before the image, which is possible. 183 */ 184 return nullptr; 185 } 186 187 /* TODO: Once the actionPacks and supportedFirmwares are merged this'll 188 * be less dangerous 189 */ 190 return actionPacks[openedFirmwareType].get(); 191 } 192 193 void addBlobId(const std::string& blob) 194 { 195 auto blobIdMatch = std::find_if( 196 blobIDs.begin(), blobIDs.end(), 197 [&blob](const std::string& iter) { return (iter == blob); }); 198 if (blobIdMatch == blobIDs.end()) 199 { 200 blobIDs.push_back(blob); 201 } 202 } 203 204 void removeBlobId(const std::string& blob) 205 { 206 blobIDs.erase(std::remove(blobIDs.begin(), blobIDs.end(), blob), 207 blobIDs.end()); 208 } 209 210 inline bool fileOpen() 211 { 212 return !lookup.empty(); 213 } 214 215 ActionStatus getVerifyStatus(); 216 ActionStatus getActionStatus(); 217 218 /** List of handlers by type. */ 219 std::vector<HandlerPack> handlers; 220 221 /** Active list of blobIDs. */ 222 std::vector<std::string> blobIDs; 223 224 /** List of handlers by transport type. */ 225 std::vector<DataHandlerPack> transports; 226 227 /** Active image session. */ 228 Session activeImage; 229 230 /** Active hash session. */ 231 Session activeHash; 232 233 /** Session for verification. */ 234 Session verifyImage; 235 236 /** Session for update. */ 237 Session updateImage; 238 239 /** A quick method for looking up a session's mechanisms and details. */ 240 std::map<std::uint16_t, Session*> lookup; 241 242 /** The firmware update state. */ 243 UpdateState state; 244 245 /** Track what firmware blobid they opened to start this sequence. */ 246 std::string openedFirmwareType; 247 248 /* preparation is triggered once we go into uploadInProgress(), but only 249 * once per full cycle, going back to notYetStarted resets this. 250 */ 251 bool preparationTriggered = false; 252 ActionMap actionPacks; 253 254 ActionStatus lastVerificationStatus = ActionStatus::unknown; 255 256 ActionStatus lastUpdateStatus = ActionStatus::unknown; 257 258 /** Portion of "flags" argument to open() which specifies the desired 259 * transport type 260 */ 261 static constexpr std::uint16_t transportMask = 0xff00; 262 }; 263 264 } // namespace ipmi_flash 265