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