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