blob: a4023277fa4240ea684c1467171be396528e2daa [file] [log] [blame]
Patrick Venture22e38752018-11-21 08:52:49 -08001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venturec7ca2912018-11-02 11:38:33 -070017#include "firmware_handler.hpp"
18
Patrick Venturea78e39f2018-11-06 18:37:06 -080019#include "image_handler.hpp"
Patrick Venture1d66fe62019-06-03 14:57:27 -070020#include "status.hpp"
Patrick Venture7dad86f2019-05-17 08:52:20 -070021#include "util.hpp"
Patrick Venturea78e39f2018-11-06 18:37:06 -080022
Patrick Venture137ad2c2018-11-06 11:30:43 -080023#include <algorithm>
Patrick Venture192d60f2018-11-06 11:11:59 -080024#include <cstdint>
Patrick Venture18235e62018-11-08 10:21:09 -080025#include <cstring>
Patrick Ventureb3b4db72019-05-15 11:30:24 -070026#include <fstream>
Patrick Venture68cf64f2018-11-06 10:46:51 -080027#include <memory>
Patrick Ventured333a872018-12-03 16:24:26 -080028#include <phosphor-logging/log.hpp>
Patrick Venturefa6c4d92018-11-02 18:34:53 -070029#include <string>
30#include <vector>
31
Patrick Ventured333a872018-12-03 16:24:26 -080032using namespace phosphor::logging;
33
Patrick Venture1d5a31c2019-05-20 11:38:22 -070034namespace ipmi_flash
Patrick Venturec7ca2912018-11-02 11:38:33 -070035{
Patrick Ventureb3b4db72019-05-15 11:30:24 -070036
Patrick Venture1d5a31c2019-05-20 11:38:22 -070037std::unique_ptr<blobs::GenericBlobInterface>
Patrick Venture148cd652018-11-06 10:59:47 -080038 FirmwareBlobHandler::CreateFirmwareBlobHandler(
Patrick Venture3ecb3502019-05-17 11:03:51 -070039 const std::vector<HandlerPack>& firmwares,
Patrick Venture74059d62019-05-17 10:40:26 -070040 const std::vector<DataHandlerPack>& transports,
Patrick Venture1d66fe62019-06-03 14:57:27 -070041 std::unique_ptr<TriggerableActionInterface> verification,
42 std::unique_ptr<TriggerableActionInterface> update)
Patrick Venture68cf64f2018-11-06 10:46:51 -080043{
Patrick Venture52854622018-11-06 12:30:00 -080044 /* There must be at least one. */
45 if (!firmwares.size())
46 {
Patrick Ventured333a872018-12-03 16:24:26 -080047 log<level::ERR>("Must provide at least one firmware handler.");
Patrick Venture52854622018-11-06 12:30:00 -080048 return nullptr;
49 }
Patrick Venture1cde5f92018-11-07 08:26:47 -080050 if (!transports.size())
51 {
52 return nullptr;
53 }
Patrick Venture52854622018-11-06 12:30:00 -080054
Patrick Venturea78e39f2018-11-06 18:37:06 -080055 std::vector<std::string> blobs;
56 for (const auto& item : firmwares)
57 {
58 blobs.push_back(item.blobName);
59 }
Patrick Venture18235e62018-11-08 10:21:09 -080060
Patrick Venture7dad86f2019-05-17 08:52:20 -070061 if (0 == std::count(blobs.begin(), blobs.end(), hashBlobId))
Patrick Venture18235e62018-11-08 10:21:09 -080062 {
63 return nullptr;
64 }
Patrick Venture4cceb8e2018-11-06 11:56:48 -080065
Patrick Venture1cde5f92018-11-07 08:26:47 -080066 std::uint16_t bitmask = 0;
67 for (const auto& item : transports)
68 {
69 /* TODO: can use std::accumulate() unless I'm mistaken. :D */
70 bitmask |= item.bitmask;
71 }
72
Patrick Venture3ecb3502019-05-17 11:03:51 -070073 return std::make_unique<FirmwareBlobHandler>(
Patrick Venture27ac5822019-05-20 17:39:31 -070074 firmwares, blobs, transports, bitmask, std::move(verification),
75 std::move(update));
Patrick Venture68cf64f2018-11-06 10:46:51 -080076}
77
Patrick Ventured6461d62018-11-09 17:30:25 -080078/* Check if the path is in our supported list (or active list). */
Patrick Venturec7ca2912018-11-02 11:38:33 -070079bool FirmwareBlobHandler::canHandleBlob(const std::string& path)
80{
Patrick Venture6032dc02019-05-17 11:01:44 -070081 return (std::count(blobIDs.begin(), blobIDs.end(), path) > 0);
Patrick Venturec7ca2912018-11-02 11:38:33 -070082}
Patrick Venture53977962018-11-02 18:59:35 -070083
Patrick Ventured6461d62018-11-09 17:30:25 -080084/*
85 * Grab the list of supported firmware.
86 *
87 * If there's an open firmware session, it'll already be present in the
88 * list as "/flash/active/image", and if the hash has started,
89 * "/flash/active/hash" regardless of mechanism. This is done in the open
90 * comamnd, no extra work is required here.
91 */
Patrick Venturec7ca2912018-11-02 11:38:33 -070092std::vector<std::string> FirmwareBlobHandler::getBlobIds()
93{
Patrick Venture4cceb8e2018-11-06 11:56:48 -080094 return blobIDs;
Patrick Venturec7ca2912018-11-02 11:38:33 -070095}
Patrick Venture53977962018-11-02 18:59:35 -070096
Patrick Ventured6461d62018-11-09 17:30:25 -080097/*
98 * Per the design, this mean abort, and this will trigger whatever
99 * appropriate actions are required to abort the process.
100 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700101bool FirmwareBlobHandler::deleteBlob(const std::string& path)
102{
Patrick Venturebcc0c772019-06-17 10:42:06 -0700103 /* This cannot be called if you have an open session to the path.
104 * You can have an open session to verify/update/hash/image, but not active*
105 *
106 * Therefore, if this is called, it's either on a blob that isn't presently
107 * open. However, there could be open blobs, so we need to close all open
108 * sessions. This closing on our is an invalid handler behavior. Therefore,
109 * we cannot close an active session. To enforce this, we only allow
110 * deleting if there isn't a file open.
Patrick Ventureffcc5502018-11-16 12:32:38 -0800111 */
Patrick Venturebcc0c772019-06-17 10:42:06 -0700112 if (fileOpen)
Patrick Ventureffcc5502018-11-16 12:32:38 -0800113 {
114 return false;
115 }
116
Patrick Venturebcc0c772019-06-17 10:42:06 -0700117 /* TODO: implement. */
118 return false;
Patrick Venturec7ca2912018-11-02 11:38:33 -0700119}
Patrick Venture53977962018-11-02 18:59:35 -0700120
Patrick Ventured6461d62018-11-09 17:30:25 -0800121/*
122 * Stat on the files will return information such as what supported
123 * transport mechanisms are available.
124 *
125 * Stat on an active file or hash will return information such as the size
126 * of the data cached, and any additional pertinent information. The
127 * blob_state on the active files will return the state of the update.
128 */
Patrick Venturee312f392019-06-04 07:44:37 -0700129bool FirmwareBlobHandler::stat(const std::string& path, blobs::BlobMeta* meta)
Patrick Venturec7ca2912018-11-02 11:38:33 -0700130{
Patrick Venture46637c82018-11-06 15:20:24 -0800131 /* We know we support this path because canHandle is called ahead */
Patrick Ventured342a952019-05-29 09:09:10 -0700132 if (path == verifyBlobId || path == activeImageBlobId ||
Patrick Venture5f562692019-05-30 16:49:46 -0700133 path == activeHashBlobId || path == updateBlobId)
Patrick Ventureffcc5502018-11-16 12:32:38 -0800134 {
Patrick Ventured342a952019-05-29 09:09:10 -0700135 /* These blobs are placeholders that indicate things, or allow actions,
136 * but are not stat-able as-is.
Patrick Ventureffcc5502018-11-16 12:32:38 -0800137 */
Patrick Ventured342a952019-05-29 09:09:10 -0700138 return false;
Patrick Venture46637c82018-11-06 15:20:24 -0800139 }
140
Patrick Ventured342a952019-05-29 09:09:10 -0700141 /* They are requesting information about the generic blob_id. */
142 meta->blobState = bitmask;
143 meta->size = 0;
144
145 /* The generic blob_ids state is only the bits related to the transport
146 * mechanisms.
147 */
148 return true;
Patrick Venturec7ca2912018-11-02 11:38:33 -0700149}
Patrick Venture53977962018-11-02 18:59:35 -0700150
Patrick Ventureda66fd82019-06-03 11:11:24 -0700151ActionStatus FirmwareBlobHandler::getActionStatus()
Patrick Venturea2d82392019-06-03 10:55:17 -0700152{
Patrick Ventureda66fd82019-06-03 11:11:24 -0700153 ActionStatus value = ActionStatus::unknown;
Patrick Venturea2d82392019-06-03 10:55:17 -0700154
155 switch (state)
156 {
157 case UpdateState::verificationPending:
Patrick Ventureda66fd82019-06-03 11:11:24 -0700158 value = ActionStatus::unknown;
Patrick Venturea2d82392019-06-03 10:55:17 -0700159 break;
160 case UpdateState::verificationStarted:
161 value = verification->status();
Patrick Ventureda66fd82019-06-03 11:11:24 -0700162 lastVerificationStatus = value;
Patrick Venturea2d82392019-06-03 10:55:17 -0700163 break;
164 case UpdateState::verificationCompleted:
Patrick Ventureda66fd82019-06-03 11:11:24 -0700165 value = lastVerificationStatus;
Patrick Venturea2d82392019-06-03 10:55:17 -0700166 break;
Patrick Venturea2d82392019-06-03 10:55:17 -0700167 case UpdateState::updatePending:
Patrick Ventureda66fd82019-06-03 11:11:24 -0700168 value = ActionStatus::unknown;
Patrick Venturea2d82392019-06-03 10:55:17 -0700169 break;
170 case UpdateState::updateStarted:
171 value = update->status();
172 lastUpdateStatus = value;
173 break;
174 case UpdateState::updateCompleted:
175 value = lastUpdateStatus;
176 break;
177 default:
178 break;
179 }
180
181 return value;
182}
183
Patrick Venturec02849b2018-11-06 17:31:15 -0800184/*
Patrick Ventured6461d62018-11-09 17:30:25 -0800185 * Return stat information on an open session. It therefore must be an active
186 * handle to either the active image or active hash.
Patrick Ventured6461d62018-11-09 17:30:25 -0800187 */
Patrick Venturee312f392019-06-04 07:44:37 -0700188bool FirmwareBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
Patrick Ventured6461d62018-11-09 17:30:25 -0800189{
Patrick Venturecc7d1602018-11-15 13:58:33 -0800190 auto item = lookup.find(session);
191 if (item == lookup.end())
192 {
193 return false;
194 }
195
Patrick Ventureb3b4db72019-05-15 11:30:24 -0700196 /* The size here refers to the size of the file -- of something analagous.
197 */
198 meta->size = (item->second->imageHandler)
199 ? item->second->imageHandler->getSize()
200 : 0;
201
202 meta->metadata.clear();
203
Patrick Ventureda66fd82019-06-03 11:11:24 -0700204 if (item->second->activePath == verifyBlobId ||
205 item->second->activePath == updateBlobId)
Patrick Ventureb3b4db72019-05-15 11:30:24 -0700206 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700207 ActionStatus value = getActionStatus();
Patrick Venture699750d2019-05-15 09:24:09 -0700208
Patrick Venturee955e072019-05-15 16:16:46 -0700209 meta->metadata.push_back(static_cast<std::uint8_t>(value));
210
211 /* Change the firmware handler's state and the blob's stat value
212 * depending.
213 */
Patrick Ventureda66fd82019-06-03 11:11:24 -0700214 if (value == ActionStatus::success || value == ActionStatus::failed)
Patrick Venturee955e072019-05-15 16:16:46 -0700215 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700216 if (item->second->activePath == verifyBlobId)
Patrick Venturee955e072019-05-15 16:16:46 -0700217 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700218 state = UpdateState::verificationCompleted;
Patrick Venturee955e072019-05-15 16:16:46 -0700219 }
220 else
221 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700222 /* item->second->activePath == updateBlobId */
223 state = UpdateState::updateCompleted;
Patrick Venturee955e072019-05-15 16:16:46 -0700224 }
Patrick Venture40d7ffc2019-05-30 17:12:06 -0700225
Patrick Venturef1f0f652019-06-03 09:10:19 -0700226 item->second->flags &= ~blobs::StateFlags::committing;
227
Patrick Ventureda66fd82019-06-03 11:11:24 -0700228 if (value == ActionStatus::success)
Patrick Venturef1f0f652019-06-03 09:10:19 -0700229 {
230 item->second->flags |= blobs::StateFlags::committed;
231 }
232 else
233 {
234 item->second->flags |= blobs::StateFlags::commit_error;
235 }
236 }
Patrick Venture40d7ffc2019-05-30 17:12:06 -0700237 }
Patrick Venturecc7d1602018-11-15 13:58:33 -0800238
Patrick Venturee955e072019-05-15 16:16:46 -0700239 /* The blobState here relates to an active sesion, so we should return the
240 * flags used to open this session.
241 */
242 meta->blobState = item->second->flags;
243
Patrick Venturecc7d1602018-11-15 13:58:33 -0800244 /* The metadata blob returned comes from the data handler... it's used for
245 * instance, in P2A bridging to get required information about the mapping,
246 * and is the "opposite" of the lpc writemeta requirement.
247 */
Patrick Venturecc7d1602018-11-15 13:58:33 -0800248 if (item->second->dataHandler)
249 {
Patrick Venture74304642019-01-17 09:31:04 -0800250 auto bytes = item->second->dataHandler->readMeta();
Patrick Venturecc7d1602018-11-15 13:58:33 -0800251 meta->metadata.insert(meta->metadata.begin(), bytes.begin(),
252 bytes.end());
253 }
254
Patrick Venturecc7d1602018-11-15 13:58:33 -0800255 return true;
Patrick Ventured6461d62018-11-09 17:30:25 -0800256}
257
258/*
Patrick Venturec02849b2018-11-06 17:31:15 -0800259 * If you open /flash/image or /flash/tarball, or /flash/hash it will
260 * interpret the open flags and perform whatever actions are required for
261 * that update process. The session returned can be used immediately for
262 * sending data down, without requiring one to open the new active file.
263 *
264 * If you open the active flash image or active hash it will let you
265 * overwrite pieces, depending on the state.
266 *
267 * Once the verification process has started the active files cannot be
268 * opened.
269 *
270 * You can only have one open session at a time. Which means, you can only
271 * have one file open at a time. Trying to open the hash blob_id while you
272 * still have the flash image blob_id open will fail. Opening the flash
273 * blob_id when it is already open will fail.
274 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700275bool FirmwareBlobHandler::open(uint16_t session, uint16_t flags,
276 const std::string& path)
277{
Patrick Venturec02849b2018-11-06 17:31:15 -0800278 /* Is there an open session already? We only allow one at a time.
Patrick Venture6e307a72018-11-09 18:21:17 -0800279 *
Patrick Venture7c8b97e2018-11-08 09:14:30 -0800280 * Further on this, if there's an active session to the hash we don't allow
281 * re-opening the image, and if we have the image open, we don't allow
282 * opening the hash. This design decision may be re-evaluated, and changed
283 * to only allow one session per object type (of the two types). But,
284 * consider if the hash is open, do we want to allow writing to the image?
285 * And why would we? But, really, the point of no-return is once the
286 * verification process has begun -- which is done via commit() on the hash
287 * blob_id, we no longer want to allow updating the contents.
Patrick Venture53977962018-11-02 18:59:35 -0700288 */
Patrick Venturec02849b2018-11-06 17:31:15 -0800289 if (fileOpen)
290 {
291 return false;
292 }
293
Patrick Venture723113f2019-06-05 09:38:35 -0700294 /* The active blobs are only meant to indicate status that something has
295 * opened the image file or the hash file.
Patrick Ventureffcc5502018-11-16 12:32:38 -0800296 */
Patrick Venture19f5d882019-05-30 14:34:55 -0700297 if (path == activeImageBlobId || path == activeHashBlobId)
298 {
299 /* 2a) are they opening the active image? this can only happen if they
300 * already started one (due to canHandleBlob's behavior).
301 */
302 /* 2b) are they opening the active hash? this can only happen if they
303 * already started one (due to canHandleBlob's behavior).
304 */
305 return false;
306 }
307
Patrick Venture723113f2019-06-05 09:38:35 -0700308 /* Check that they've opened for writing - read back not currently
309 * supported.
310 */
311 if ((flags & blobs::OpenFlags::write) == 0)
312 {
313 return false;
314 }
315
316 /* Because canHandleBlob is called before open, we know that if they try to
317 * open the verifyBlobId, they're in a state where it's present.
318 */
319
320 switch (state)
321 {
322 case UpdateState::uploadInProgress:
323 /* Unreachable code because if it's started a file is open. */
324 break;
325 case UpdateState::verificationPending:
326 /* Handle opening the verifyBlobId --> we know the image and hash
327 * aren't open because of the fileOpen check. They can still open
328 * other files from this state to transition back into
329 * uploadInProgress.
330 *
331 * The file must be opened for writing, but no transport mechanism
332 * specified since it's irrelevant.
333 */
334 if (path == verifyBlobId)
335 {
336 verifyImage.flags = flags;
Patrick Venture723113f2019-06-05 09:38:35 -0700337
338 lookup[session] = &verifyImage;
339
340 fileOpen = true;
341 return true;
342 }
343 break;
344 case UpdateState::verificationStarted:
345 case UpdateState::verificationCompleted:
346 /* Unreachable code because if it's started a file is open. */
347 return false;
348 case UpdateState::updatePending:
349 {
350 /* When in this state, they can only open the updateBlobId */
351 if (path == updateBlobId)
352 {
353 updateImage.flags = flags;
Patrick Venture723113f2019-06-05 09:38:35 -0700354
355 lookup[session] = &updateImage;
356
357 fileOpen = true;
358 return true;
359 }
360 else
361 {
362 return false;
363 }
364 }
365 case UpdateState::updateStarted:
366 case UpdateState::updateCompleted:
367 /* Unreachable code because if it's started a file is open. */
368 break;
369 default:
370 break;
371 }
372
373 /* There are two abstractions at play, how you get the data and how you
374 * handle that data. such that, whether the data comes from the PCI bridge
375 * or LPC bridge is not connected to whether the data goes into a static
376 * layout flash update or a UBI tarball.
377 */
378
Patrick Venturec02849b2018-11-06 17:31:15 -0800379 /* Check the flags for the transport mechanism: if none match we don't
Patrick Venture18235e62018-11-08 10:21:09 -0800380 * support what they request.
381 */
Patrick Venture1cde5f92018-11-07 08:26:47 -0800382 if ((flags & bitmask) == 0)
Patrick Venturec02849b2018-11-06 17:31:15 -0800383 {
384 return false;
385 }
386
Patrick Venture18235e62018-11-08 10:21:09 -0800387 /* How are they expecting to copy this data? */
388 auto d = std::find_if(
389 transports.begin(), transports.end(),
390 [&flags](const auto& iter) { return (iter.bitmask & flags); });
391 if (d == transports.end())
Patrick Venturec02849b2018-11-06 17:31:15 -0800392 {
Patrick Venture18235e62018-11-08 10:21:09 -0800393 return false;
394 }
395
396 /* We found the transport handler they requested, no surprise since
397 * above we verify they selected at least one we wanted.
398 */
Patrick Venturec02849b2018-11-06 17:31:15 -0800399
Patrick Venture6e307a72018-11-09 18:21:17 -0800400 /* Elsewhere I do this check by checking "if ::ipmi" because that's the
401 * only non-external data pathway -- but this is just a more generic
402 * approach to that.
403 */
404 if (d->handler)
405 {
406 /* If the data handler open call fails, open fails. */
407 if (!d->handler->open())
408 {
409 return false;
410 }
411 }
412
Patrick Venture70e30bf2019-01-17 10:29:28 -0800413 /* Do we have a file handler for the type of file they're opening.
414 * Note: This should only fail if something is somehow crazy wrong.
415 * Since the canHandle() said yes, and that's tied into the list of explicit
416 * firmware handers (and file handlers, like this'll know where to write the
417 * tarball, etc).
Patrick Venture18235e62018-11-08 10:21:09 -0800418 */
Patrick Venture18235e62018-11-08 10:21:09 -0800419 auto h = std::find_if(
420 handlers.begin(), handlers.end(),
421 [&path](const auto& iter) { return (iter.blobName == path); });
422 if (h == handlers.end())
423 {
424 return false;
425 }
426
427 /* Ok, so we found a handler that matched, so call open() */
428 if (!h->handler->open(path))
429 {
430 return false;
431 }
432
Patrick Venture70e30bf2019-01-17 10:29:28 -0800433 Session* curr;
434 const std::string* active;
435
Patrick Venture7dad86f2019-05-17 08:52:20 -0700436 if (path == hashBlobId)
Patrick Venture70e30bf2019-01-17 10:29:28 -0800437 {
438 /* 2c) are they opening the /flash/hash ? (to start the process) */
439 curr = &activeHash;
Patrick Venture7dad86f2019-05-17 08:52:20 -0700440 active = &activeHashBlobId;
Patrick Venture70e30bf2019-01-17 10:29:28 -0800441 }
442 else
443 {
444 curr = &activeImage;
Patrick Venture7dad86f2019-05-17 08:52:20 -0700445 active = &activeImageBlobId;
Patrick Venture70e30bf2019-01-17 10:29:28 -0800446 }
447
Patrick Venture18235e62018-11-08 10:21:09 -0800448 curr->flags = flags;
449 curr->dataHandler = d->handler;
450 curr->imageHandler = h->handler;
451
452 lookup[session] = curr;
453
Patrick Ventureefba42d2019-05-24 10:48:16 -0700454 addBlobId(*active);
Patrick Venture930c7b72019-05-24 11:11:08 -0700455 removeBlobId(verifyBlobId);
Patrick Venturedb253bf2018-11-09 19:36:03 -0800456
Patrick Venture12233c52019-05-16 09:26:59 -0700457 state = UpdateState::uploadInProgress;
Patrick Venture991910a2018-11-09 19:43:48 -0800458 fileOpen = true;
459
Patrick Venture18235e62018-11-08 10:21:09 -0800460 return true;
Patrick Venturec7ca2912018-11-02 11:38:33 -0700461}
Patrick Venture53977962018-11-02 18:59:35 -0700462
Patrick Venture18235e62018-11-08 10:21:09 -0800463/**
464 * The write command really just grabs the data from wherever it is and sends it
465 * to the image handler. It's the image handler's responsibility to deal with
466 * the data provided.
Patrick Ventured6461d62018-11-09 17:30:25 -0800467 *
468 * This receives a session from the blob manager, therefore it is always called
469 * between open() and close().
Patrick Venture18235e62018-11-08 10:21:09 -0800470 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700471bool FirmwareBlobHandler::write(uint16_t session, uint32_t offset,
472 const std::vector<uint8_t>& data)
473{
Patrick Venture18235e62018-11-08 10:21:09 -0800474 auto item = lookup.find(session);
475 if (item == lookup.end())
476 {
477 return false;
478 }
479
Patrick Ventureb1b68fc2018-11-09 09:37:04 -0800480 /* Prevent writing during verification. */
481 if (state == UpdateState::verificationStarted)
482 {
483 return false;
484 }
485
Patrick Venture4e2fdcd2019-05-30 14:58:57 -0700486 /* Prevent writing to the verification or update blobs. */
487 if (item->second->activePath == verifyBlobId ||
488 item->second->activePath == updateBlobId)
Patrick Venture8af15eb2019-05-15 09:39:22 -0700489 {
490 return false;
491 }
Patrick Venture699750d2019-05-15 09:24:09 -0700492
Patrick Venture18235e62018-11-08 10:21:09 -0800493 std::vector<std::uint8_t> bytes;
494
Patrick Venture05abf7e2018-11-09 11:02:56 -0800495 if (item->second->flags & UpdateFlags::ipmi)
Patrick Venture18235e62018-11-08 10:21:09 -0800496 {
497 bytes = data;
498 }
499 else
500 {
501 /* little endian required per design, and so on, but TODO: do endianness
502 * with boost.
503 */
504 struct ExtChunkHdr header;
505
506 if (data.size() != sizeof(header))
507 {
508 return false;
509 }
510
511 std::memcpy(&header, data.data(), data.size());
512 bytes = item->second->dataHandler->copyFrom(header.length);
513 }
514
515 return item->second->imageHandler->write(offset, bytes);
Patrick Venturec7ca2912018-11-02 11:38:33 -0700516}
Patrick Venture18235e62018-11-08 10:21:09 -0800517
Patrick Venture8c535332018-11-08 15:58:00 -0800518/*
519 * If the active session (image or hash) is over LPC, this allows
520 * configuring it. This option is only available before you start
521 * writing data for the given item (image or hash). This will return
522 * false at any other part. -- the lpc handler portion will know to return
523 * false.
524 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700525bool FirmwareBlobHandler::writeMeta(uint16_t session, uint32_t offset,
526 const std::vector<uint8_t>& data)
527{
Patrick Venture8c535332018-11-08 15:58:00 -0800528 auto item = lookup.find(session);
529 if (item == lookup.end())
530 {
531 return false;
532 }
533
Patrick Venture05abf7e2018-11-09 11:02:56 -0800534 if (item->second->flags & UpdateFlags::ipmi)
Patrick Venture8c535332018-11-08 15:58:00 -0800535 {
536 return false;
537 }
538
Patrick Ventured56097a2019-05-15 09:47:55 -0700539 /* Prevent writing meta to the verification blob (it has no data handler).
540 */
541 if (item->second->dataHandler)
542 {
543 return item->second->dataHandler->writeMeta(data);
544 }
Patrick Venture699750d2019-05-15 09:24:09 -0700545
Patrick Ventured56097a2019-05-15 09:47:55 -0700546 return false;
Patrick Venturec7ca2912018-11-02 11:38:33 -0700547}
Patrick Venture8c535332018-11-08 15:58:00 -0800548
Patrick Ventured6461d62018-11-09 17:30:25 -0800549/*
Patrick Venture7dad86f2019-05-17 08:52:20 -0700550 * If this command is called on the session for the verifyBlobId, it'll
Patrick Ventured6461d62018-11-09 17:30:25 -0800551 * trigger a systemd service `verify_image.service` to attempt to verify
Patrick Ventureffcc5502018-11-16 12:32:38 -0800552 * the image.
553 *
554 * For this file to have opened, the other two must be closed, which means any
555 * out-of-band transport mechanism involved is closed.
Patrick Ventured6461d62018-11-09 17:30:25 -0800556 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700557bool FirmwareBlobHandler::commit(uint16_t session,
558 const std::vector<uint8_t>& data)
559{
Patrick Ventureffcc5502018-11-16 12:32:38 -0800560 auto item = lookup.find(session);
561 if (item == lookup.end())
562 {
563 return false;
564 }
565
Patrick Venture1a406fe2019-05-31 07:29:56 -0700566 /* You can only commit on the verifyBlodId or updateBlobId */
567 if (item->second->activePath != verifyBlobId &&
568 item->second->activePath != updateBlobId)
Patrick Ventureffcc5502018-11-16 12:32:38 -0800569 {
Patrick Venture1a406fe2019-05-31 07:29:56 -0700570 std::fprintf(stderr, "path: '%s' not expected for commit\n",
571 item->second->activePath.c_str());
Patrick Ventureffcc5502018-11-16 12:32:38 -0800572 return false;
573 }
574
Patrick Venture433cbc32019-05-30 09:53:10 -0700575 switch (state)
Patrick Ventureffcc5502018-11-16 12:32:38 -0800576 {
Patrick Venture1a406fe2019-05-31 07:29:56 -0700577 case UpdateState::verificationPending:
578 /* Set state to committing. */
579 item->second->flags |= blobs::StateFlags::committing;
580 return triggerVerification();
Patrick Venture433cbc32019-05-30 09:53:10 -0700581 case UpdateState::verificationStarted:
582 /* Calling repeatedly has no effect within an update process. */
583 return true;
584 case UpdateState::verificationCompleted:
585 /* Calling after the verification process has completed returns
586 * failure. */
587 return false;
Patrick Venture1a406fe2019-05-31 07:29:56 -0700588 case UpdateState::updatePending:
Patrick Venture433cbc32019-05-30 09:53:10 -0700589 item->second->flags |= blobs::StateFlags::committing;
Patrick Venture1a406fe2019-05-31 07:29:56 -0700590 return triggerUpdate();
Patrick Venture0079d892019-05-31 11:27:44 -0700591 case UpdateState::updateStarted:
592 /* Calling repeatedly has no effect within an update process. */
593 return true;
Patrick Venture1a406fe2019-05-31 07:29:56 -0700594 default:
595 return false;
Patrick Ventureffcc5502018-11-16 12:32:38 -0800596 }
Patrick Venturec7ca2912018-11-02 11:38:33 -0700597}
Patrick Ventured6461d62018-11-09 17:30:25 -0800598
599/*
600 * Close must be called on the firmware image before triggering
601 * verification via commit. Once the verification is complete, you can
602 * then close the hash file.
603 *
604 * If the `verify_image.service` returned success, closing the hash file
605 * will have a specific behavior depending on the update. If it's UBI,
606 * it'll perform the install. If it's static layout, it'll do nothing. The
607 * verify_image service in the static layout case is responsible for placing
608 * the file in the correct staging position.
609 */
Patrick Venturec7ca2912018-11-02 11:38:33 -0700610bool FirmwareBlobHandler::close(uint16_t session)
611{
Patrick Venture68bb1432018-11-09 20:08:48 -0800612 auto item = lookup.find(session);
613 if (item == lookup.end())
614 {
615 return false;
616 }
617
Patrick Venturee95dbb62019-06-05 09:59:29 -0700618 switch (state)
Patrick Ventureffcc5502018-11-16 12:32:38 -0800619 {
Patrick Venturee95dbb62019-06-05 09:59:29 -0700620 case UpdateState::uploadInProgress:
621 /* They are closing a data pathway (image, tarball, hash). */
622 state = UpdateState::verificationPending;
Patrick Venture85ae86b2019-06-05 09:18:40 -0700623
Patrick Venturee95dbb62019-06-05 09:59:29 -0700624 /* Add verify blob ID now that we can expect it. */
625 addBlobId(verifyBlobId);
626 break;
627 case UpdateState::verificationPending:
628 /* They haven't triggered, therefore closing is uninteresting.
629 */
630 break;
631 case UpdateState::verificationStarted:
Patrick Ventured5741022019-06-17 09:08:35 -0700632 /* Abort without checking to see if it happened to finish. Require
633 * the caller to stat() deliberately.
Patrick Venturee95dbb62019-06-05 09:59:29 -0700634 */
Patrick Ventured5741022019-06-17 09:08:35 -0700635 abortVerification();
636 abortProcess();
637 break;
Patrick Venturee95dbb62019-06-05 09:59:29 -0700638 case UpdateState::verificationCompleted:
639 if (lastVerificationStatus == ActionStatus::success)
640 {
641 state = UpdateState::updatePending;
642 addBlobId(updateBlobId);
643 removeBlobId(verifyBlobId);
644 }
645 else
646 {
647 /* TODO: Verification failed, what now? */
648 }
649 break;
650 case UpdateState::updatePending:
651 /* They haven't triggered the update, therefore this is
652 * uninteresting. */
653 break;
654 case UpdateState::updateStarted:
Patrick Venture49731712019-06-17 10:04:02 -0700655 /* Abort without checking to see if it happened to finish. Require
656 * the caller to stat() deliberately.
657 */
658 abortUpdate();
659 abortProcess();
Patrick Venturee95dbb62019-06-05 09:59:29 -0700660 break;
661 case UpdateState::updateCompleted:
662 if (lastUpdateStatus == ActionStatus::failed)
663 {
664 /* TODO: lOG something? */
665 }
Patrick Venture930c7b72019-05-24 11:11:08 -0700666
Patrick Venturee95dbb62019-06-05 09:59:29 -0700667 state = UpdateState::notYetStarted;
668 removeBlobId(updateBlobId);
669 removeBlobId(activeImageBlobId);
670 removeBlobId(activeHashBlobId);
671 break;
672 default:
673 break;
Patrick Ventureffcc5502018-11-16 12:32:38 -0800674 }
675
Patrick Venture68bb1432018-11-09 20:08:48 -0800676 if (item->second->dataHandler)
677 {
678 item->second->dataHandler->close();
679 }
Patrick Ventureffcc5502018-11-16 12:32:38 -0800680 if (item->second->imageHandler)
681 {
682 item->second->imageHandler->close();
683 }
684
Patrick Venture68bb1432018-11-09 20:08:48 -0800685 lookup.erase(item);
Patrick Venture991910a2018-11-09 19:43:48 -0800686 fileOpen = false;
Patrick Venture68bb1432018-11-09 20:08:48 -0800687 return true;
Patrick Venturec7ca2912018-11-02 11:38:33 -0700688}
Patrick Ventured6461d62018-11-09 17:30:25 -0800689
Patrick Venturec7ca2912018-11-02 11:38:33 -0700690bool FirmwareBlobHandler::expire(uint16_t session)
691{
692 return false;
693}
Patrick Ventured6461d62018-11-09 17:30:25 -0800694
695/*
696 * Currently, the design does not provide this with a function, however,
697 * it will likely change to support reading data back.
698 */
699std::vector<uint8_t> FirmwareBlobHandler::read(uint16_t session,
700 uint32_t offset,
701 uint32_t requestedSize)
702{
703 return {};
704}
705
Patrick Ventured5741022019-06-17 09:08:35 -0700706void FirmwareBlobHandler::abortProcess()
707{
708 /* Closing of open files is handled from close() -- Reaching here from
709 * delete may never be supported.
710 */
711 removeBlobId(verifyBlobId);
712 removeBlobId(updateBlobId);
713 removeBlobId(activeImageBlobId);
714 removeBlobId(activeHashBlobId);
715
716 state = UpdateState::notYetStarted;
717}
718
719void FirmwareBlobHandler::abortVerification()
720{
721 verification->abort();
722}
723
Patrick Ventureffcc5502018-11-16 12:32:38 -0800724bool FirmwareBlobHandler::triggerVerification()
725{
Patrick Venture1d66fe62019-06-03 14:57:27 -0700726 bool result = verification->trigger();
Patrick Venture3ecb3502019-05-17 11:03:51 -0700727 if (result)
Patrick Venturecabc1172018-11-16 16:14:26 -0800728 {
Patrick Venture453f06a2019-01-17 10:02:12 -0800729 state = UpdateState::verificationStarted;
Patrick Venturecabc1172018-11-16 16:14:26 -0800730 }
Patrick Venturecabc1172018-11-16 16:14:26 -0800731
Patrick Venture3ecb3502019-05-17 11:03:51 -0700732 return result;
Patrick Ventureffcc5502018-11-16 12:32:38 -0800733}
734
Patrick Venture49731712019-06-17 10:04:02 -0700735void FirmwareBlobHandler::abortUpdate()
736{
737 update->abort();
738}
739
Patrick Venture1a406fe2019-05-31 07:29:56 -0700740bool FirmwareBlobHandler::triggerUpdate()
741{
Patrick Venture1d66fe62019-06-03 14:57:27 -0700742 bool result = update->trigger();
Patrick Venture1a406fe2019-05-31 07:29:56 -0700743 if (result)
744 {
745 state = UpdateState::updateStarted;
746 }
747
748 return result;
749}
750
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700751} // namespace ipmi_flash