xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision c72503f3fc356ff5c983c7202c66623179b275dc)
1729dae72SJennifer Lee /*
2729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation
3729dae72SJennifer Lee //
4729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License");
5729dae72SJennifer Lee // you may not use this file except in compliance with the License.
6729dae72SJennifer Lee // You may obtain a copy of the License at
7729dae72SJennifer Lee //
8729dae72SJennifer Lee //      http://www.apache.org/licenses/LICENSE-2.0
9729dae72SJennifer Lee //
10729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software
11729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS,
12729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13729dae72SJennifer Lee // See the License for the specific language governing permissions and
14729dae72SJennifer Lee // limitations under the License.
15729dae72SJennifer Lee */
16729dae72SJennifer Lee #pragma once
17729dae72SJennifer Lee 
18d61e5194STejas Patil #include "bmcweb_config.h"
19d61e5194STejas Patil 
203ccb3adbSEd Tanous #include "app.hpp"
213ccb3adbSEd Tanous #include "dbus_utility.hpp"
225b90429aSEd Tanous #include "error_messages.hpp"
23757178a5SEd Tanous #include "generated/enums/update_service.hpp"
240ed80c8cSGeorge Liu #include "multipart_parser.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "query.hpp"
273ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
28a8e884fcSEd Tanous #include "task.hpp"
295b90429aSEd Tanous #include "task_messages.hpp"
3008d81adaSJohn Edward Broadbent #include "utils/collection.hpp"
313ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
325b90429aSEd Tanous #include "utils/json_utils.hpp"
333ccb3adbSEd Tanous #include "utils/sw_utils.hpp"
343ccb3adbSEd Tanous 
35e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
36ef4c65b7SEd Tanous #include <boost/url/format.hpp>
371e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
383ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
39d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
401214b7e7SGunnar Mills 
412b73119cSGeorge Liu #include <array>
420ed80c8cSGeorge Liu #include <filesystem>
437cb59f65SEd Tanous #include <optional>
447cb59f65SEd Tanous #include <string>
452b73119cSGeorge Liu #include <string_view>
462b73119cSGeorge Liu 
471abe55efSEd Tanous namespace redfish
481abe55efSEd Tanous {
4927826b5fSEd Tanous 
500e7de46fSAndrew Geissler // Match signals added on software path
51cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
5259d494eeSPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
53cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
5459d494eeSPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
550e7de46fSAndrew Geissler // Only allow one update at a time
56cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
570e7de46fSAndrew Geissler static bool fwUpdateInProgress = false;
5886adcd6dSAndrew Geissler // Timer for software available
59cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
60271584abSEd Tanous static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
6186adcd6dSAndrew Geissler 
62df254f2cSEd Tanous inline void cleanUp()
6386adcd6dSAndrew Geissler {
6486adcd6dSAndrew Geissler     fwUpdateInProgress = false;
6586adcd6dSAndrew Geissler     fwUpdateMatcher = nullptr;
664cde5d90SJames Feist     fwUpdateErrorMatcher = nullptr;
6786adcd6dSAndrew Geissler }
68df254f2cSEd Tanous 
69df254f2cSEd Tanous inline void activateImage(const std::string& objPath,
7086adcd6dSAndrew Geissler                           const std::string& service)
7186adcd6dSAndrew Geissler {
7262598e31SEd Tanous     BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
739ae226faSGeorge Liu     sdbusplus::asio::setProperty(
749ae226faSGeorge Liu         *crow::connections::systemBus, service, objPath,
759ae226faSGeorge Liu         "xyz.openbmc_project.Software.Activation", "RequestedActivation",
769ae226faSGeorge Liu         "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
778b24275dSEd Tanous         [](const boost::system::error_code& ec) {
788b24275dSEd Tanous         if (ec)
7986adcd6dSAndrew Geissler         {
8062598e31SEd Tanous             BMCWEB_LOG_DEBUG("error_code = {}", ec);
8162598e31SEd Tanous             BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
8286adcd6dSAndrew Geissler         }
839ae226faSGeorge Liu     });
8486adcd6dSAndrew Geissler }
850554c984SAndrew Geissler 
860554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
870554c984SAndrew Geissler // then no asyncResp updates will occur
888d1b46d7Szhanghch05 static void
898d1b46d7Szhanghch05     softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9059d494eeSPatrick Williams                            sdbusplus::message_t& m, task::Payload&& payload)
9186adcd6dSAndrew Geissler {
9280f79a40SMichael Shen     dbus::utility::DBusInterfacesMap interfacesProperties;
9386adcd6dSAndrew Geissler 
9486adcd6dSAndrew Geissler     sdbusplus::message::object_path objPath;
9586adcd6dSAndrew Geissler 
9686adcd6dSAndrew Geissler     m.read(objPath, interfacesProperties);
9786adcd6dSAndrew Geissler 
9862598e31SEd Tanous     BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
99e3eb3d63SEd Tanous     for (const auto& interface : interfacesProperties)
10086adcd6dSAndrew Geissler     {
10162598e31SEd Tanous         BMCWEB_LOG_DEBUG("interface = {}", interface.first);
10286adcd6dSAndrew Geissler 
10386adcd6dSAndrew Geissler         if (interface.first == "xyz.openbmc_project.Software.Activation")
10486adcd6dSAndrew Geissler         {
10586adcd6dSAndrew Geissler             // Retrieve service and activate
1062b73119cSGeorge Liu             constexpr std::array<std::string_view, 1> interfaces = {
1072b73119cSGeorge Liu                 "xyz.openbmc_project.Software.Activation"};
1082b73119cSGeorge Liu             dbus::utility::getDbusObject(
1092b73119cSGeorge Liu                 objPath.str, interfaces,
110a3e65892SEd Tanous                 [objPath, asyncResp, payload(std::move(payload))](
1118b24275dSEd Tanous                     const boost::system::error_code& ec,
112a3e65892SEd Tanous                     const std::vector<
113a3e65892SEd Tanous                         std::pair<std::string, std::vector<std::string>>>&
114a3e65892SEd Tanous                         objInfo) mutable {
1158b24275dSEd Tanous                 if (ec)
11686adcd6dSAndrew Geissler                 {
11762598e31SEd Tanous                     BMCWEB_LOG_DEBUG("error_code = {}", ec);
11862598e31SEd Tanous                     BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
1190554c984SAndrew Geissler                     if (asyncResp)
1200554c984SAndrew Geissler                     {
12186adcd6dSAndrew Geissler                         messages::internalError(asyncResp->res);
1220554c984SAndrew Geissler                     }
12386adcd6dSAndrew Geissler                     cleanUp();
12486adcd6dSAndrew Geissler                     return;
12586adcd6dSAndrew Geissler                 }
12686adcd6dSAndrew Geissler                 // Ensure we only got one service back
12786adcd6dSAndrew Geissler                 if (objInfo.size() != 1)
12886adcd6dSAndrew Geissler                 {
12962598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid Object Size {}", objInfo.size());
1300554c984SAndrew Geissler                     if (asyncResp)
1310554c984SAndrew Geissler                     {
13286adcd6dSAndrew Geissler                         messages::internalError(asyncResp->res);
1330554c984SAndrew Geissler                     }
13486adcd6dSAndrew Geissler                     cleanUp();
13586adcd6dSAndrew Geissler                     return;
13686adcd6dSAndrew Geissler                 }
13786adcd6dSAndrew Geissler                 // cancel timer only when
13886adcd6dSAndrew Geissler                 // xyz.openbmc_project.Software.Activation interface
13986adcd6dSAndrew Geissler                 // is added
14086adcd6dSAndrew Geissler                 fwAvailableTimer = nullptr;
14186adcd6dSAndrew Geissler 
14286adcd6dSAndrew Geissler                 activateImage(objPath.str, objInfo[0].first);
1430554c984SAndrew Geissler                 if (asyncResp)
1440554c984SAndrew Geissler                 {
14532898ceaSJames Feist                     std::shared_ptr<task::TaskData> task =
14632898ceaSJames Feist                         task::TaskData::createTask(
1478b24275dSEd Tanous                             [](const boost::system::error_code& ec2,
14859d494eeSPatrick Williams                                sdbusplus::message_t& msg,
1491214b7e7SGunnar Mills                                const std::shared_ptr<task::TaskData>&
1501214b7e7SGunnar Mills                                    taskData) {
1518b24275dSEd Tanous                         if (ec2)
15232898ceaSJames Feist                         {
15332898ceaSJames Feist                             return task::completed;
15432898ceaSJames Feist                         }
15532898ceaSJames Feist 
15632898ceaSJames Feist                         std::string iface;
157b9d36b47SEd Tanous                         dbus::utility::DBusPropertiesMap values;
158fd9ab9e1SJames Feist 
159002d39b4SEd Tanous                         std::string index = std::to_string(taskData->index);
16032898ceaSJames Feist                         msg.read(iface, values);
161fd9ab9e1SJames Feist 
162002d39b4SEd Tanous                         if (iface == "xyz.openbmc_project.Software.Activation")
163fd9ab9e1SJames Feist                         {
1640fb5b505SGayathri Leburu                             const std::string* state = nullptr;
165b9d36b47SEd Tanous                             for (const auto& property : values)
16632898ceaSJames Feist                             {
167b9d36b47SEd Tanous                                 if (property.first == "Activation")
168b9d36b47SEd Tanous                                 {
1690fb5b505SGayathri Leburu                                     state = std::get_if<std::string>(
170b9d36b47SEd Tanous                                         &property.second);
1710fb5b505SGayathri Leburu                                     if (state == nullptr)
172b9d36b47SEd Tanous                                     {
173002d39b4SEd Tanous                                         taskData->messages.emplace_back(
174002d39b4SEd Tanous                                             messages::internalError());
175b9d36b47SEd Tanous                                         return task::completed;
176b9d36b47SEd Tanous                                     }
177b9d36b47SEd Tanous                                 }
178b9d36b47SEd Tanous                             }
17932898ceaSJames Feist 
18032898ceaSJames Feist                             if (state == nullptr)
18132898ceaSJames Feist                             {
182b9d36b47SEd Tanous                                 return !task::completed;
18332898ceaSJames Feist                             }
18432898ceaSJames Feist 
18511ba3979SEd Tanous                             if (state->ends_with("Invalid") ||
18611ba3979SEd Tanous                                 state->ends_with("Failed"))
18732898ceaSJames Feist                             {
18832898ceaSJames Feist                                 taskData->state = "Exception";
18932898ceaSJames Feist                                 taskData->status = "Warning";
19032898ceaSJames Feist                                 taskData->messages.emplace_back(
191e5d5006bSJames Feist                                     messages::taskAborted(index));
19232898ceaSJames Feist                                 return task::completed;
19332898ceaSJames Feist                             }
19432898ceaSJames Feist 
19511ba3979SEd Tanous                             if (state->ends_with("Staged"))
19632898ceaSJames Feist                             {
197fd9ab9e1SJames Feist                                 taskData->state = "Stopping";
198fd9ab9e1SJames Feist                                 taskData->messages.emplace_back(
199fd9ab9e1SJames Feist                                     messages::taskPaused(index));
200fd9ab9e1SJames Feist 
201fd9ab9e1SJames Feist                                 // its staged, set a long timer to
202fd9ab9e1SJames Feist                                 // allow them time to complete the
203fd9ab9e1SJames Feist                                 // update (probably cycle the
204fd9ab9e1SJames Feist                                 // system) if this expires then
2058ece0e45SEd Tanous                                 // task will be canceled
206002d39b4SEd Tanous                                 taskData->extendTimer(std::chrono::hours(5));
20732898ceaSJames Feist                                 return !task::completed;
20832898ceaSJames Feist                             }
20932898ceaSJames Feist 
21011ba3979SEd Tanous                             if (state->ends_with("Active"))
21132898ceaSJames Feist                             {
21232898ceaSJames Feist                                 taskData->messages.emplace_back(
213002d39b4SEd Tanous                                     messages::taskCompletedOK(index));
21432898ceaSJames Feist                                 taskData->state = "Completed";
21532898ceaSJames Feist                                 return task::completed;
21632898ceaSJames Feist                             }
217fd9ab9e1SJames Feist                         }
2180fda0f12SGeorge Liu                         else if (
2190fda0f12SGeorge Liu                             iface ==
2200fda0f12SGeorge Liu                             "xyz.openbmc_project.Software.ActivationProgress")
221fd9ab9e1SJames Feist                         {
222b9d36b47SEd Tanous                             const uint8_t* progress = nullptr;
223b9d36b47SEd Tanous                             for (const auto& property : values)
224fd9ab9e1SJames Feist                             {
225b9d36b47SEd Tanous                                 if (property.first == "Progress")
226b9d36b47SEd Tanous                                 {
2270fb5b505SGayathri Leburu                                     progress =
2280fb5b505SGayathri Leburu                                         std::get_if<uint8_t>(&property.second);
2290fb5b505SGayathri Leburu                                     if (progress == nullptr)
230b9d36b47SEd Tanous                                     {
231002d39b4SEd Tanous                                         taskData->messages.emplace_back(
232002d39b4SEd Tanous                                             messages::internalError());
233b9d36b47SEd Tanous                                         return task::completed;
234fd9ab9e1SJames Feist                                     }
235b9d36b47SEd Tanous                                 }
236b9d36b47SEd Tanous                             }
237fd9ab9e1SJames Feist 
238fd9ab9e1SJames Feist                             if (progress == nullptr)
239fd9ab9e1SJames Feist                             {
240b9d36b47SEd Tanous                                 return !task::completed;
241fd9ab9e1SJames Feist                             }
2420fb5b505SGayathri Leburu                             taskData->percentComplete = *progress;
243fd9ab9e1SJames Feist                             taskData->messages.emplace_back(
2440fb5b505SGayathri Leburu                                 messages::taskProgressChanged(index,
2450fb5b505SGayathri Leburu                                                               *progress));
246fd9ab9e1SJames Feist 
247fd9ab9e1SJames Feist                             // if we're getting status updates it's
248fd9ab9e1SJames Feist                             // still alive, update timer
249002d39b4SEd Tanous                             taskData->extendTimer(std::chrono::minutes(5));
250fd9ab9e1SJames Feist                         }
25132898ceaSJames Feist 
25232898ceaSJames Feist                         // as firmware update often results in a
25332898ceaSJames Feist                         // reboot, the task  may never "complete"
25432898ceaSJames Feist                         // unless it is an error
25532898ceaSJames Feist 
25632898ceaSJames Feist                         return !task::completed;
25732898ceaSJames Feist                     },
2580fda0f12SGeorge Liu                             "type='signal',interface='org.freedesktop.DBus.Properties',"
259fd9ab9e1SJames Feist                             "member='PropertiesChanged',path='" +
26032898ceaSJames Feist                                 objPath.str + "'");
26132898ceaSJames Feist                     task->startTimer(std::chrono::minutes(5));
26232898ceaSJames Feist                     task->populateResp(asyncResp->res);
263a3e65892SEd Tanous                     task->payload.emplace(std::move(payload));
2640554c984SAndrew Geissler                 }
26586adcd6dSAndrew Geissler                 fwUpdateInProgress = false;
2662b73119cSGeorge Liu             });
26762bafc01SPatrick Williams 
26862bafc01SPatrick Williams             break;
26986adcd6dSAndrew Geissler         }
27086adcd6dSAndrew Geissler     }
27186adcd6dSAndrew Geissler }
27286adcd6dSAndrew Geissler 
2738549b951SMyung Bae inline void afterAvailbleTimerAsyncWait(
2748549b951SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2758549b951SMyung Bae     const boost::system::error_code& ec)
2768549b951SMyung Bae {
2778549b951SMyung Bae     cleanUp();
2788549b951SMyung Bae     if (ec == boost::asio::error::operation_aborted)
2798549b951SMyung Bae     {
2808549b951SMyung Bae         // expected, we were canceled before the timer completed.
2818549b951SMyung Bae         return;
2828549b951SMyung Bae     }
2838549b951SMyung Bae     BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
2848549b951SMyung Bae     BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
2858549b951SMyung Bae     if (ec)
2868549b951SMyung Bae     {
2878549b951SMyung Bae         BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
2888549b951SMyung Bae         return;
2898549b951SMyung Bae     }
2908549b951SMyung Bae     if (asyncResp)
2918549b951SMyung Bae     {
2928549b951SMyung Bae         redfish::messages::internalError(asyncResp->res);
2938549b951SMyung Bae     }
2948549b951SMyung Bae }
2958549b951SMyung Bae 
2968549b951SMyung Bae inline void
2978549b951SMyung Bae     handleUpdateErrorType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2988549b951SMyung Bae                           const std::string& url, const std::string& type)
2998549b951SMyung Bae {
3008549b951SMyung Bae     if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
3018549b951SMyung Bae     {
3028549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3038549b951SMyung Bae                                          "Invalid archive");
3048549b951SMyung Bae     }
3058549b951SMyung Bae     else if (type ==
3068549b951SMyung Bae              "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
3078549b951SMyung Bae     {
3088549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3098549b951SMyung Bae                                          "Invalid manifest");
3108549b951SMyung Bae     }
3118549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
3128549b951SMyung Bae     {
3138549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3148549b951SMyung Bae                                          "Invalid image format");
3158549b951SMyung Bae     }
3168549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
3178549b951SMyung Bae     {
3188549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3198549b951SMyung Bae                                          "Image version already exists");
3208549b951SMyung Bae 
3218549b951SMyung Bae         redfish::messages::resourceAlreadyExists(
3228549b951SMyung Bae             asyncResp->res, "UpdateService", "Version", "uploaded version");
3238549b951SMyung Bae     }
3248549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
3258549b951SMyung Bae     {
3268549b951SMyung Bae         redfish::messages::resourceExhaustion(asyncResp->res, url);
3278549b951SMyung Bae     }
3284034a652SMyung Bae     else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
3298549b951SMyung Bae     {
3304034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3314034a652SMyung Bae                                          "Incompatible image version");
3324034a652SMyung Bae     }
3334034a652SMyung Bae     else if (type ==
3344034a652SMyung Bae              "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
3354034a652SMyung Bae     {
3364034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3374034a652SMyung Bae                                          "Update Access Key Expired");
3384034a652SMyung Bae     }
3394034a652SMyung Bae     else if (type ==
3404034a652SMyung Bae              "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
3414034a652SMyung Bae     {
3424034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3434034a652SMyung Bae                                          "Invalid image signature");
3444034a652SMyung Bae     }
3454034a652SMyung Bae     else if (type ==
3464034a652SMyung Bae                  "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
3474034a652SMyung Bae              type == "xyz.openbmc_project.Software.Version.Error.HostFile")
3484034a652SMyung Bae     {
3494034a652SMyung Bae         BMCWEB_LOG_ERROR("Software Image Error type={}", type);
3508549b951SMyung Bae         redfish::messages::internalError(asyncResp->res);
3518549b951SMyung Bae     }
3524034a652SMyung Bae     else
3534034a652SMyung Bae     {
3544034a652SMyung Bae         // Unrelated error types. Ignored
3554034a652SMyung Bae         BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
3564034a652SMyung Bae         return;
3574034a652SMyung Bae     }
3584034a652SMyung Bae     // Clear the timer
3594034a652SMyung Bae     fwAvailableTimer = nullptr;
3608549b951SMyung Bae }
3618549b951SMyung Bae 
3628549b951SMyung Bae inline void
3638549b951SMyung Bae     afterUpdateErrorMatcher(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3648549b951SMyung Bae                             const std::string& url, sdbusplus::message_t& m)
3658549b951SMyung Bae {
36680f79a40SMichael Shen     dbus::utility::DBusInterfacesMap interfacesProperties;
3678549b951SMyung Bae     sdbusplus::message::object_path objPath;
3688549b951SMyung Bae     m.read(objPath, interfacesProperties);
3698549b951SMyung Bae     BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
3708549b951SMyung Bae     for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
3718549b951SMyung Bae              interface : interfacesProperties)
3728549b951SMyung Bae     {
3738549b951SMyung Bae         if (interface.first == "xyz.openbmc_project.Logging.Entry")
3748549b951SMyung Bae         {
3758549b951SMyung Bae             for (const std::pair<std::string, dbus::utility::DbusVariantType>&
3768549b951SMyung Bae                      value : interface.second)
3778549b951SMyung Bae             {
3788549b951SMyung Bae                 if (value.first != "Message")
3798549b951SMyung Bae                 {
3808549b951SMyung Bae                     continue;
3818549b951SMyung Bae                 }
3828549b951SMyung Bae                 const std::string* type =
3838549b951SMyung Bae                     std::get_if<std::string>(&value.second);
3848549b951SMyung Bae                 if (type == nullptr)
3858549b951SMyung Bae                 {
3868549b951SMyung Bae                     // if this was our message, timeout will cover it
3878549b951SMyung Bae                     return;
3888549b951SMyung Bae                 }
3898549b951SMyung Bae                 handleUpdateErrorType(asyncResp, url, *type);
3908549b951SMyung Bae             }
3918549b951SMyung Bae         }
3928549b951SMyung Bae     }
3938549b951SMyung Bae }
3948549b951SMyung Bae 
3950554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
3960554c984SAndrew Geissler // then no asyncResp updates will occur
397f5139334SEd Tanous inline void monitorForSoftwareAvailable(
3988d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3998d1b46d7Szhanghch05     const crow::Request& req, const std::string& url,
4005d138943SGunnar Mills     int timeoutTimeSeconds = 25)
40186adcd6dSAndrew Geissler {
40286adcd6dSAndrew Geissler     // Only allow one FW update at a time
403e05aec50SEd Tanous     if (fwUpdateInProgress)
40486adcd6dSAndrew Geissler     {
4050554c984SAndrew Geissler         if (asyncResp)
4060554c984SAndrew Geissler         {
40786adcd6dSAndrew Geissler             messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
4080554c984SAndrew Geissler         }
40986adcd6dSAndrew Geissler         return;
41086adcd6dSAndrew Geissler     }
41186adcd6dSAndrew Geissler 
4128e8245dbSEd Tanous     if (req.ioService == nullptr)
4138e8245dbSEd Tanous     {
4148e8245dbSEd Tanous         messages::internalError(asyncResp->res);
4158e8245dbSEd Tanous         return;
4168e8245dbSEd Tanous     }
4178e8245dbSEd Tanous 
4180554c984SAndrew Geissler     fwAvailableTimer =
419271584abSEd Tanous         std::make_unique<boost::asio::steady_timer>(*req.ioService);
42086adcd6dSAndrew Geissler 
421271584abSEd Tanous     fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
42286adcd6dSAndrew Geissler 
42386adcd6dSAndrew Geissler     fwAvailableTimer->async_wait(
4248549b951SMyung Bae         std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
4258549b951SMyung Bae 
426a3e65892SEd Tanous     task::Payload payload(req);
42759d494eeSPatrick Williams     auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
42862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Match fired");
429a3e65892SEd Tanous         softwareInterfaceAdded(asyncResp, m, std::move(payload));
43086adcd6dSAndrew Geissler     };
43186adcd6dSAndrew Geissler 
43286adcd6dSAndrew Geissler     fwUpdateInProgress = true;
43386adcd6dSAndrew Geissler 
43459d494eeSPatrick Williams     fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
43586adcd6dSAndrew Geissler         *crow::connections::systemBus,
43686adcd6dSAndrew Geissler         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
43786adcd6dSAndrew Geissler         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
43886adcd6dSAndrew Geissler         callback);
4394cde5d90SJames Feist 
44059d494eeSPatrick Williams     fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
4414cde5d90SJames Feist         *crow::connections::systemBus,
442e1cc4828SBrian Ma         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
443e1cc4828SBrian Ma         "member='InterfacesAdded',"
444e1cc4828SBrian Ma         "path='/xyz/openbmc_project/logging'",
4458549b951SMyung Bae         std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
44686adcd6dSAndrew Geissler }
447729dae72SJennifer Lee 
448757178a5SEd Tanous inline std::optional<boost::urls::url>
449757178a5SEd Tanous     parseSimpleUpdateUrl(std::string imageURI,
450f86bcc87SEd Tanous                          std::optional<std::string> transferProtocol,
451f86bcc87SEd Tanous                          crow::Response& res)
452f86bcc87SEd Tanous {
453f86bcc87SEd Tanous     if (imageURI.find("://") == std::string::npos)
454f86bcc87SEd Tanous     {
455f86bcc87SEd Tanous         if (imageURI.starts_with("/"))
456f86bcc87SEd Tanous         {
457f86bcc87SEd Tanous             messages::actionParameterValueTypeError(
458f86bcc87SEd Tanous                 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
459f86bcc87SEd Tanous             return std::nullopt;
460f86bcc87SEd Tanous         }
461f86bcc87SEd Tanous         if (!transferProtocol)
462f86bcc87SEd Tanous         {
463f86bcc87SEd Tanous             messages::actionParameterValueTypeError(
464f86bcc87SEd Tanous                 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
465f86bcc87SEd Tanous             return std::nullopt;
466f86bcc87SEd Tanous         }
467e5cf777eSEd Tanous         // OpenBMC currently only supports TFTP or HTTPS
468757178a5SEd Tanous         if (*transferProtocol == "TFTP")
469757178a5SEd Tanous         {
470757178a5SEd Tanous             imageURI = "tftp://" + imageURI;
471757178a5SEd Tanous         }
472e5cf777eSEd Tanous         else if (*transferProtocol == "HTTPS")
473e5cf777eSEd Tanous         {
474e5cf777eSEd Tanous             imageURI = "https://" + imageURI;
475e5cf777eSEd Tanous         }
476757178a5SEd Tanous         else
477f86bcc87SEd Tanous         {
478f86bcc87SEd Tanous             messages::actionParameterNotSupported(res, "TransferProtocol",
479f86bcc87SEd Tanous                                                   *transferProtocol);
480f86bcc87SEd Tanous             BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
481f86bcc87SEd Tanous                              *transferProtocol);
482f86bcc87SEd Tanous             return std::nullopt;
483f86bcc87SEd Tanous         }
484f86bcc87SEd Tanous     }
485f86bcc87SEd Tanous 
486f86bcc87SEd Tanous     boost::system::result<boost::urls::url> url =
487f86bcc87SEd Tanous         boost::urls::parse_absolute_uri(imageURI);
488f86bcc87SEd Tanous     if (!url)
489f86bcc87SEd Tanous     {
490f86bcc87SEd Tanous         messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
491f86bcc87SEd Tanous                                                 "UpdateService.SimpleUpdate");
492f86bcc87SEd Tanous 
493f86bcc87SEd Tanous         return std::nullopt;
494f86bcc87SEd Tanous     }
495f86bcc87SEd Tanous     url->normalize();
496f86bcc87SEd Tanous 
497757178a5SEd Tanous     if (url->scheme() == "tftp")
498757178a5SEd Tanous     {
499757178a5SEd Tanous         if (url->encoded_path().size() < 2)
500757178a5SEd Tanous         {
501757178a5SEd Tanous             messages::actionParameterNotSupported(res, "ImageURI",
502757178a5SEd Tanous                                                   url->buffer());
503757178a5SEd Tanous             return std::nullopt;
504757178a5SEd Tanous         }
505757178a5SEd Tanous     }
506e5cf777eSEd Tanous     else if (url->scheme() == "https")
507e5cf777eSEd Tanous     {
508e5cf777eSEd Tanous         // Empty paths default to "/"
509e5cf777eSEd Tanous         if (url->encoded_path().empty())
510e5cf777eSEd Tanous         {
511e5cf777eSEd Tanous             url->set_encoded_path("/");
512e5cf777eSEd Tanous         }
513e5cf777eSEd Tanous     }
514757178a5SEd Tanous     else
515f86bcc87SEd Tanous     {
516f86bcc87SEd Tanous         messages::actionParameterNotSupported(res, "ImageURI", imageURI);
517f86bcc87SEd Tanous         return std::nullopt;
518f86bcc87SEd Tanous     }
519757178a5SEd Tanous 
520757178a5SEd Tanous     if (url->encoded_path().empty())
521f86bcc87SEd Tanous     {
522757178a5SEd Tanous         messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
523757178a5SEd Tanous                                                 "UpdateService.SimpleUpdate");
524f86bcc87SEd Tanous         return std::nullopt;
525f86bcc87SEd Tanous     }
526757178a5SEd Tanous 
527757178a5SEd Tanous     return *url;
528f86bcc87SEd Tanous }
529f86bcc87SEd Tanous 
530e5cf777eSEd Tanous inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
531e5cf777eSEd Tanous                           const boost::urls::url_view_base& url)
532e5cf777eSEd Tanous {
533e5cf777eSEd Tanous     messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
534e5cf777eSEd Tanous                                           url.buffer());
535e5cf777eSEd Tanous }
536e5cf777eSEd Tanous 
5376b0f66bdSEd Tanous inline void doTftpUpdate(const crow::Request& req,
5386b0f66bdSEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
539757178a5SEd Tanous                          const boost::urls::url_view_base& url)
5406b0f66bdSEd Tanous {
541*c72503f3SEd Tanous     if (!BMCWEB_INSECURE_TFTP_UPDATE)
542*c72503f3SEd Tanous     {
5436b0f66bdSEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
544757178a5SEd Tanous                                               url.buffer());
5456b0f66bdSEd Tanous         return;
546*c72503f3SEd Tanous     }
547757178a5SEd Tanous 
548757178a5SEd Tanous     std::string path(url.encoded_path());
549757178a5SEd Tanous     if (path.size() < 2)
550757178a5SEd Tanous     {
551757178a5SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
552757178a5SEd Tanous                                               url.buffer());
553757178a5SEd Tanous         return;
554757178a5SEd Tanous     }
555757178a5SEd Tanous     // TFTP expects a path without a /
556757178a5SEd Tanous     path.erase(0, 1);
557757178a5SEd Tanous     std::string host(url.encoded_host_and_port());
558757178a5SEd Tanous     BMCWEB_LOG_DEBUG("Server: {} File: {}", host, path);
5596b0f66bdSEd Tanous 
5606b0f66bdSEd Tanous     // Setup callback for when new software detected
5616b0f66bdSEd Tanous     // Give TFTP 10 minutes to complete
5626b0f66bdSEd Tanous     monitorForSoftwareAvailable(
5636b0f66bdSEd Tanous         asyncResp, req,
5646b0f66bdSEd Tanous         "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", 600);
5656b0f66bdSEd Tanous 
5666b0f66bdSEd Tanous     // TFTP can take up to 10 minutes depending on image size and
5676b0f66bdSEd Tanous     // connection speed. Return to caller as soon as the TFTP operation
5686b0f66bdSEd Tanous     // has been started. The callback above will ensure the activate
5696b0f66bdSEd Tanous     // is started once the download has completed
5706b0f66bdSEd Tanous     redfish::messages::success(asyncResp->res);
5716b0f66bdSEd Tanous 
5726b0f66bdSEd Tanous     // Call TFTP service
5736b0f66bdSEd Tanous     crow::connections::systemBus->async_method_call(
5746b0f66bdSEd Tanous         [](const boost::system::error_code& ec) {
5756b0f66bdSEd Tanous         if (ec)
5766b0f66bdSEd Tanous         {
5776b0f66bdSEd Tanous             // messages::internalError(asyncResp->res);
5786b0f66bdSEd Tanous             cleanUp();
5796b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("error_code = {}", ec);
5806b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
5816b0f66bdSEd Tanous         }
5826b0f66bdSEd Tanous         else
5836b0f66bdSEd Tanous         {
5846b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("Call to DownloaViaTFTP Success");
5856b0f66bdSEd Tanous         }
5866b0f66bdSEd Tanous     },
5876b0f66bdSEd Tanous         "xyz.openbmc_project.Software.Download",
5886b0f66bdSEd Tanous         "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
589757178a5SEd Tanous         "DownloadViaTFTP", path, host);
5906b0f66bdSEd Tanous }
5916b0f66bdSEd Tanous 
592f5139334SEd Tanous inline void handleUpdateServiceSimpleUpdateAction(
593f5139334SEd Tanous     crow::App& app, const crow::Request& req,
594f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
5950554c984SAndrew Geissler {
5963ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
59745ca1b86SEd Tanous     {
59845ca1b86SEd Tanous         return;
59945ca1b86SEd Tanous     }
60045ca1b86SEd Tanous 
6010554c984SAndrew Geissler     std::optional<std::string> transferProtocol;
6020554c984SAndrew Geissler     std::string imageURI;
6030554c984SAndrew Geissler 
60462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
6050554c984SAndrew Geissler 
6060554c984SAndrew Geissler     // User can pass in both TransferProtocol and ImageURI parameters or
6074e0453b1SGunnar Mills     // they can pass in just the ImageURI with the transfer protocol
6084e0453b1SGunnar Mills     // embedded within it.
6090554c984SAndrew Geissler     // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
6100554c984SAndrew Geissler     // 2) ImageURI:tftp://1.1.1.1/myfile.bin
6110554c984SAndrew Geissler 
612002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
613002d39b4SEd Tanous                                    transferProtocol, "ImageURI", imageURI))
6140554c984SAndrew Geissler     {
61562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
6160554c984SAndrew Geissler         return;
6170554c984SAndrew Geissler     }
618f5139334SEd Tanous 
619757178a5SEd Tanous     std::optional<boost::urls::url> url =
620757178a5SEd Tanous         parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
621757178a5SEd Tanous     if (!url)
6220554c984SAndrew Geissler     {
6230554c984SAndrew Geissler         return;
6240554c984SAndrew Geissler     }
625757178a5SEd Tanous     if (url->scheme() == "tftp")
626757178a5SEd Tanous     {
627757178a5SEd Tanous         doTftpUpdate(req, asyncResp, *url);
628757178a5SEd Tanous     }
629e5cf777eSEd Tanous     else if (url->scheme() == "https")
630e5cf777eSEd Tanous     {
631e5cf777eSEd Tanous         doHttpsUpdate(asyncResp, *url);
632e5cf777eSEd Tanous     }
633757178a5SEd Tanous     else
634757178a5SEd Tanous     {
635757178a5SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
636757178a5SEd Tanous                                               url->buffer());
637757178a5SEd Tanous         return;
638757178a5SEd Tanous     }
6390554c984SAndrew Geissler 
64062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
641729dae72SJennifer Lee }
642729dae72SJennifer Lee 
6430ed80c8cSGeorge Liu inline void uploadImageFile(crow::Response& res, std::string_view body)
6440ed80c8cSGeorge Liu {
6452c6ffdb0SEd Tanous     std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
6462c6ffdb0SEd Tanous 
64762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
6480ed80c8cSGeorge Liu     std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
6490ed80c8cSGeorge Liu                                     std::ofstream::trunc);
6500ed80c8cSGeorge Liu     // set the permission of the file to 640
65189492a15SPatrick Williams     std::filesystem::perms permission = std::filesystem::perms::owner_read |
65289492a15SPatrick Williams                                         std::filesystem::perms::group_read;
6530ed80c8cSGeorge Liu     std::filesystem::permissions(filepath, permission);
6540ed80c8cSGeorge Liu     out << body;
6550ed80c8cSGeorge Liu 
6560ed80c8cSGeorge Liu     if (out.bad())
6570ed80c8cSGeorge Liu     {
6580ed80c8cSGeorge Liu         messages::internalError(res);
6590ed80c8cSGeorge Liu         cleanUp();
6600ed80c8cSGeorge Liu     }
6610ed80c8cSGeorge Liu }
6620ed80c8cSGeorge Liu 
6630ed80c8cSGeorge Liu inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6640ed80c8cSGeorge Liu                          const std::string& applyTime)
6650ed80c8cSGeorge Liu {
6660ed80c8cSGeorge Liu     std::string applyTimeNewVal;
6670ed80c8cSGeorge Liu     if (applyTime == "Immediate")
6680ed80c8cSGeorge Liu     {
6690ed80c8cSGeorge Liu         applyTimeNewVal =
6700ed80c8cSGeorge Liu             "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
6710ed80c8cSGeorge Liu     }
6720ed80c8cSGeorge Liu     else if (applyTime == "OnReset")
6730ed80c8cSGeorge Liu     {
6740ed80c8cSGeorge Liu         applyTimeNewVal =
6750ed80c8cSGeorge Liu             "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
6760ed80c8cSGeorge Liu     }
6770ed80c8cSGeorge Liu     else
6780ed80c8cSGeorge Liu     {
67962598e31SEd Tanous         BMCWEB_LOG_INFO(
68062598e31SEd Tanous             "ApplyTime value is not in the list of acceptable values");
6810ed80c8cSGeorge Liu         messages::propertyValueNotInList(asyncResp->res, applyTime,
6820ed80c8cSGeorge Liu                                          "ApplyTime");
6830ed80c8cSGeorge Liu         return;
6840ed80c8cSGeorge Liu     }
6850ed80c8cSGeorge Liu 
686d02aad39SEd Tanous     setDbusProperty(asyncResp, "xyz.openbmc_project.Settings",
687d02aad39SEd Tanous                     sdbusplus::message::object_path(
688d02aad39SEd Tanous                         "/xyz/openbmc_project/software/apply_time"),
689d02aad39SEd Tanous                     "xyz.openbmc_project.Software.ApplyTime",
690d02aad39SEd Tanous                     "RequestedApplyTime", "ApplyTime", applyTimeNewVal);
6910ed80c8cSGeorge Liu }
6920ed80c8cSGeorge Liu 
6930ed80c8cSGeorge Liu inline void
6940ed80c8cSGeorge Liu     updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6956b54e4e0SEd Tanous                            const crow::Request& req,
6960ed80c8cSGeorge Liu                            const MultipartParser& parser)
6970ed80c8cSGeorge Liu {
6980ed80c8cSGeorge Liu     const std::string* uploadData = nullptr;
6990ed80c8cSGeorge Liu     std::optional<std::string> applyTime = "OnReset";
7000ed80c8cSGeorge Liu     bool targetFound = false;
7010ed80c8cSGeorge Liu     for (const FormPart& formpart : parser.mime_fields)
7020ed80c8cSGeorge Liu     {
7030ed80c8cSGeorge Liu         boost::beast::http::fields::const_iterator it =
7040ed80c8cSGeorge Liu             formpart.fields.find("Content-Disposition");
7050ed80c8cSGeorge Liu         if (it == formpart.fields.end())
7060ed80c8cSGeorge Liu         {
70762598e31SEd Tanous             BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
7080ed80c8cSGeorge Liu             return;
7090ed80c8cSGeorge Liu         }
71062598e31SEd Tanous         BMCWEB_LOG_INFO("Parsing value {}", it->value());
7110ed80c8cSGeorge Liu 
7120ed80c8cSGeorge Liu         // The construction parameters of param_list must start with `;`
7130ed80c8cSGeorge Liu         size_t index = it->value().find(';');
7140ed80c8cSGeorge Liu         if (index == std::string::npos)
7150ed80c8cSGeorge Liu         {
7160ed80c8cSGeorge Liu             continue;
7170ed80c8cSGeorge Liu         }
7180ed80c8cSGeorge Liu 
71989492a15SPatrick Williams         for (const auto& param :
7200ed80c8cSGeorge Liu              boost::beast::http::param_list{it->value().substr(index)})
7210ed80c8cSGeorge Liu         {
7220ed80c8cSGeorge Liu             if (param.first != "name" || param.second.empty())
7230ed80c8cSGeorge Liu             {
7240ed80c8cSGeorge Liu                 continue;
7250ed80c8cSGeorge Liu             }
7260ed80c8cSGeorge Liu 
7270ed80c8cSGeorge Liu             if (param.second == "UpdateParameters")
7280ed80c8cSGeorge Liu             {
7290ed80c8cSGeorge Liu                 std::vector<std::string> targets;
7300ed80c8cSGeorge Liu                 nlohmann::json content =
7310ed80c8cSGeorge Liu                     nlohmann::json::parse(formpart.content);
7327cb59f65SEd Tanous                 nlohmann::json::object_t* obj =
7337cb59f65SEd Tanous                     content.get_ptr<nlohmann::json::object_t*>();
7347cb59f65SEd Tanous                 if (obj == nullptr)
7357cb59f65SEd Tanous                 {
7367cb59f65SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, targets,
7377cb59f65SEd Tanous                                                        "UpdateParameters");
7387cb59f65SEd Tanous                     return;
7397cb59f65SEd Tanous                 }
7407cb59f65SEd Tanous 
7417cb59f65SEd Tanous                 if (!json_util::readJsonObject(
7427cb59f65SEd Tanous                         *obj, asyncResp->res, "Targets", targets,
7437cb59f65SEd Tanous                         "@Redfish.OperationApplyTime", applyTime))
7440ed80c8cSGeorge Liu                 {
7450ed80c8cSGeorge Liu                     return;
7460ed80c8cSGeorge Liu                 }
7470ed80c8cSGeorge Liu                 if (targets.size() != 1)
7480ed80c8cSGeorge Liu                 {
7497cb59f65SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, targets,
7507cb59f65SEd Tanous                                                        "Targets");
7510ed80c8cSGeorge Liu                     return;
7520ed80c8cSGeorge Liu                 }
7530ed80c8cSGeorge Liu                 if (targets[0] != "/redfish/v1/Managers/bmc")
7540ed80c8cSGeorge Liu                 {
7557cb59f65SEd Tanous                     messages::propertyValueNotInList(asyncResp->res, targets[0],
7567cb59f65SEd Tanous                                                      "Targets/0");
7570ed80c8cSGeorge Liu                     return;
7580ed80c8cSGeorge Liu                 }
7590ed80c8cSGeorge Liu                 targetFound = true;
7600ed80c8cSGeorge Liu             }
7610ed80c8cSGeorge Liu             else if (param.second == "UpdateFile")
7620ed80c8cSGeorge Liu             {
7630ed80c8cSGeorge Liu                 uploadData = &(formpart.content);
7640ed80c8cSGeorge Liu             }
7650ed80c8cSGeorge Liu         }
7660ed80c8cSGeorge Liu     }
7670ed80c8cSGeorge Liu 
7680ed80c8cSGeorge Liu     if (uploadData == nullptr)
7690ed80c8cSGeorge Liu     {
77062598e31SEd Tanous         BMCWEB_LOG_ERROR("Upload data is NULL");
7710ed80c8cSGeorge Liu         messages::propertyMissing(asyncResp->res, "UpdateFile");
7720ed80c8cSGeorge Liu         return;
7730ed80c8cSGeorge Liu     }
7740ed80c8cSGeorge Liu     if (!targetFound)
7750ed80c8cSGeorge Liu     {
7760ed80c8cSGeorge Liu         messages::propertyMissing(asyncResp->res, "targets");
7770ed80c8cSGeorge Liu         return;
7780ed80c8cSGeorge Liu     }
7790ed80c8cSGeorge Liu 
7800ed80c8cSGeorge Liu     setApplyTime(asyncResp, *applyTime);
7810ed80c8cSGeorge Liu 
7826b54e4e0SEd Tanous     // Setup callback for when new software detected
7836b54e4e0SEd Tanous     monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService");
7846b54e4e0SEd Tanous 
7850ed80c8cSGeorge Liu     uploadImageFile(asyncResp->res, *uploadData);
7860ed80c8cSGeorge Liu }
7870ed80c8cSGeorge Liu 
788c2051d11SEd Tanous inline void
789c2051d11SEd Tanous     handleUpdateServicePost(App& app, const crow::Request& req,
790c2051d11SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
791c2051d11SEd Tanous {
7923ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
793c2051d11SEd Tanous     {
794c2051d11SEd Tanous         return;
795c2051d11SEd Tanous     }
796b33a4327SNinad Palsule     std::string_view contentType = req.getHeaderValue("Content-Type");
797b33a4327SNinad Palsule 
79862598e31SEd Tanous     BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
799b33a4327SNinad Palsule 
800b33a4327SNinad Palsule     // Make sure that content type is application/octet-stream or
801b33a4327SNinad Palsule     // multipart/form-data
80218f8f608SEd Tanous     if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
803b33a4327SNinad Palsule     {
804b33a4327SNinad Palsule         // Setup callback for when new software detected
805b33a4327SNinad Palsule         monitorForSoftwareAvailable(asyncResp, req,
806b33a4327SNinad Palsule                                     "/redfish/v1/UpdateService");
807b33a4327SNinad Palsule 
808b33a4327SNinad Palsule         uploadImageFile(asyncResp->res, req.body());
809b33a4327SNinad Palsule     }
810b33a4327SNinad Palsule     else if (contentType.starts_with("multipart/form-data"))
811b33a4327SNinad Palsule     {
812b33a4327SNinad Palsule         MultipartParser parser;
813c2051d11SEd Tanous 
8140ed80c8cSGeorge Liu         ParserError ec = parser.parse(req);
8150ed80c8cSGeorge Liu         if (ec != ParserError::PARSER_SUCCESS)
8160ed80c8cSGeorge Liu         {
8170ed80c8cSGeorge Liu             // handle error
81862598e31SEd Tanous             BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
81962598e31SEd Tanous                              static_cast<int>(ec));
8200ed80c8cSGeorge Liu             messages::internalError(asyncResp->res);
8210ed80c8cSGeorge Liu             return;
8220ed80c8cSGeorge Liu         }
8236b54e4e0SEd Tanous 
8246b54e4e0SEd Tanous         updateMultipartContext(asyncResp, req, parser);
825c2051d11SEd Tanous     }
826b33a4327SNinad Palsule     else
827b33a4327SNinad Palsule     {
82862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
829b33a4327SNinad Palsule         asyncResp->res.result(boost::beast::http::status::bad_request);
830b33a4327SNinad Palsule     }
831b33a4327SNinad Palsule }
832c2051d11SEd Tanous 
833f5139334SEd Tanous inline void
834f5139334SEd Tanous     handleUpdateServiceGet(App& app, const crow::Request& req,
835f5139334SEd Tanous                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
8361abe55efSEd Tanous {
8373ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
83845ca1b86SEd Tanous     {
83945ca1b86SEd Tanous         return;
84045ca1b86SEd Tanous     }
8418d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
8420ed80c8cSGeorge Liu         "#UpdateService.v1_11_1.UpdateService";
8438d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
8448d1b46d7Szhanghch05     asyncResp->res.jsonValue["Id"] = "UpdateService";
845002d39b4SEd Tanous     asyncResp->res.jsonValue["Description"] = "Service for Software Update";
8468d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Update Service";
8474dc23f3fSEd Tanous 
8487e860f15SJohn Edward Broadbent     asyncResp->res.jsonValue["HttpPushUri"] =
8494dc23f3fSEd Tanous         "/redfish/v1/UpdateService/update";
8500ed80c8cSGeorge Liu     asyncResp->res.jsonValue["MultipartHttpPushUri"] =
8510ed80c8cSGeorge Liu         "/redfish/v1/UpdateService/update";
8524dc23f3fSEd Tanous 
8530f74e643SEd Tanous     // UpdateService cannot be disabled
8548d1b46d7Szhanghch05     asyncResp->res.jsonValue["ServiceEnabled"] = true;
8551476687dSEd Tanous     asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
8561476687dSEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory";
857d61e5194STejas Patil     // Get the MaxImageSizeBytes
85825b54dbaSEd Tanous     asyncResp->res.jsonValue["MaxImageSizeBytes"] = BMCWEB_HTTP_BODY_LIMIT *
859f5139334SEd Tanous                                                     1024 * 1024;
860d61e5194STejas Patil 
8610554c984SAndrew Geissler     // Update Actions object.
8620554c984SAndrew Geissler     nlohmann::json& updateSvcSimpleUpdate =
863002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
8640554c984SAndrew Geissler     updateSvcSimpleUpdate["target"] =
8650554c984SAndrew Geissler         "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
866757178a5SEd Tanous 
867757178a5SEd Tanous     nlohmann::json::array_t allowed;
868e5cf777eSEd Tanous     allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
869757178a5SEd Tanous 
87025b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
87125b54dbaSEd Tanous     {
872757178a5SEd Tanous         allowed.emplace_back(update_service::TransferProtocolType::TFTP);
87325b54dbaSEd Tanous     }
874757178a5SEd Tanous 
875757178a5SEd Tanous     updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
876757178a5SEd Tanous         std::move(allowed);
877757178a5SEd Tanous 
878274dfe62SJayashankar Padath     // Get the current ApplyTime value
8791e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
8801e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
8811e1e598dSJonathan Doman         "/xyz/openbmc_project/software/apply_time",
8821e1e598dSJonathan Doman         "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
8835e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
8841e1e598dSJonathan Doman                     const std::string& applyTime) {
885274dfe62SJayashankar Padath         if (ec)
886274dfe62SJayashankar Padath         {
88762598e31SEd Tanous             BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
8888d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
889274dfe62SJayashankar Padath             return;
890274dfe62SJayashankar Padath         }
891274dfe62SJayashankar Padath 
892274dfe62SJayashankar Padath         // Store the ApplyTime Value
8931e1e598dSJonathan Doman         if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
8941e1e598dSJonathan Doman                          "RequestedApplyTimes.Immediate")
895274dfe62SJayashankar Padath         {
896002d39b4SEd Tanous             asyncResp->res.jsonValue["HttpPushUriOptions"]
8977e860f15SJohn Edward Broadbent                                     ["HttpPushUriApplyTime"]["ApplyTime"] =
8987e860f15SJohn Edward Broadbent                 "Immediate";
899274dfe62SJayashankar Padath         }
900002d39b4SEd Tanous         else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
9011e1e598dSJonathan Doman                               "RequestedApplyTimes.OnReset")
902274dfe62SJayashankar Padath         {
903002d39b4SEd Tanous             asyncResp->res.jsonValue["HttpPushUriOptions"]
9047e860f15SJohn Edward Broadbent                                     ["HttpPushUriApplyTime"]["ApplyTime"] =
9057e860f15SJohn Edward Broadbent                 "OnReset";
906274dfe62SJayashankar Padath         }
9071e1e598dSJonathan Doman     });
908f5139334SEd Tanous }
909f5139334SEd Tanous 
910f5139334SEd Tanous inline void handleUpdateServicePatch(
911f5139334SEd Tanous     App& app, const crow::Request& req,
912f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
913f5139334SEd Tanous {
9143ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
91545ca1b86SEd Tanous     {
91645ca1b86SEd Tanous         return;
91745ca1b86SEd Tanous     }
91862598e31SEd Tanous     BMCWEB_LOG_DEBUG("doPatch...");
919fa1a5a38SJayashankar Padath 
920274dfe62SJayashankar Padath     std::optional<std::string> applyTime;
9217cb59f65SEd Tanous     if (!json_util::readJsonPatch(
9227cb59f65SEd Tanous             req, asyncResp->res,
9237cb59f65SEd Tanous             "HttpPushUriOptions/HttpPushUriApplyTime/ApplyTime", applyTime))
924274dfe62SJayashankar Padath     {
925274dfe62SJayashankar Padath         return;
926274dfe62SJayashankar Padath     }
927274dfe62SJayashankar Padath 
928274dfe62SJayashankar Padath     if (applyTime)
929fa1a5a38SJayashankar Padath     {
9300ed80c8cSGeorge Liu         setApplyTime(asyncResp, *applyTime);
931fa1a5a38SJayashankar Padath     }
932729dae72SJennifer Lee }
933729dae72SJennifer Lee 
934f5139334SEd Tanous inline void handleUpdateServiceFirmwareInventoryCollectionGet(
935f5139334SEd Tanous     App& app, const crow::Request& req,
936f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
9371abe55efSEd Tanous {
9383ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
93945ca1b86SEd Tanous     {
94045ca1b86SEd Tanous         return;
94145ca1b86SEd Tanous     }
9428d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
9430f74e643SEd Tanous         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
9448d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] =
9450f74e643SEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory";
946002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
94708d81adaSJohn Edward Broadbent     const std::array<const std::string_view, 1> iface = {
948e99073f5SGeorge Liu         "xyz.openbmc_project.Software.Version"};
9496c4eb9deSJennifer Lee 
95008d81adaSJohn Edward Broadbent     redfish::collection_util::getCollectionMembers(
95108d81adaSJohn Edward Broadbent         asyncResp,
952f5139334SEd Tanous         boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
953f5139334SEd Tanous         "/xyz/openbmc_project/software");
954729dae72SJennifer Lee }
955f5139334SEd Tanous 
95687d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */
957f5139334SEd Tanous inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
95887d84729SAndrew Geissler                             const std::string& purpose)
95987d84729SAndrew Geissler {
960eee0013eSWilly Tu     if (purpose == sw_util::bmcPurpose)
96187d84729SAndrew Geissler     {
962ac106bf6SEd Tanous         nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
9631476687dSEd Tanous         nlohmann::json::object_t item;
9641476687dSEd Tanous         item["@odata.id"] = "/redfish/v1/Managers/bmc";
965b2ba3072SPatrick Williams         relatedItem.emplace_back(std::move(item));
966ac106bf6SEd Tanous         asyncResp->res.jsonValue["RelatedItem@odata.count"] =
967ac106bf6SEd Tanous             relatedItem.size();
96887d84729SAndrew Geissler     }
969eee0013eSWilly Tu     else if (purpose == sw_util::biosPurpose)
97087d84729SAndrew Geissler     {
971ac106bf6SEd Tanous         nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
9721476687dSEd Tanous         nlohmann::json::object_t item;
9731476687dSEd Tanous         item["@odata.id"] = "/redfish/v1/Systems/system/Bios";
974b2ba3072SPatrick Williams         relatedItem.emplace_back(std::move(item));
975ac106bf6SEd Tanous         asyncResp->res.jsonValue["RelatedItem@odata.count"] =
976ac106bf6SEd Tanous             relatedItem.size();
97787d84729SAndrew Geissler     }
97887d84729SAndrew Geissler     else
97987d84729SAndrew Geissler     {
980bf2ddedeSCarson Labrado         BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
98187d84729SAndrew Geissler     }
98287d84729SAndrew Geissler }
98387d84729SAndrew Geissler 
984af24660dSWilly Tu inline void
985af24660dSWilly Tu     getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
986af24660dSWilly Tu                        const std::string& service, const std::string& path,
987af24660dSWilly Tu                        const std::string& swId)
988af24660dSWilly Tu {
989d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
990d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, service, path,
991d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Version",
992af24660dSWilly Tu         [asyncResp,
9938b24275dSEd Tanous          swId](const boost::system::error_code& ec,
994af24660dSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
9958b24275dSEd Tanous         if (ec)
996af24660dSWilly Tu         {
997af24660dSWilly Tu             messages::internalError(asyncResp->res);
998af24660dSWilly Tu             return;
999af24660dSWilly Tu         }
1000d1bde9e5SKrzysztof Grobelny 
1001af24660dSWilly Tu         const std::string* swInvPurpose = nullptr;
1002af24660dSWilly Tu         const std::string* version = nullptr;
1003d1bde9e5SKrzysztof Grobelny 
1004d1bde9e5SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
1005d1bde9e5SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1006d1bde9e5SKrzysztof Grobelny             swInvPurpose, "Version", version);
1007d1bde9e5SKrzysztof Grobelny 
1008d1bde9e5SKrzysztof Grobelny         if (!success)
1009af24660dSWilly Tu         {
1010d1bde9e5SKrzysztof Grobelny             messages::internalError(asyncResp->res);
1011d1bde9e5SKrzysztof Grobelny             return;
1012af24660dSWilly Tu         }
1013af24660dSWilly Tu 
1014af24660dSWilly Tu         if (swInvPurpose == nullptr)
1015af24660dSWilly Tu         {
101662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1017af24660dSWilly Tu             messages::internalError(asyncResp->res);
1018af24660dSWilly Tu             return;
1019af24660dSWilly Tu         }
1020af24660dSWilly Tu 
102162598e31SEd Tanous         BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
1022af24660dSWilly Tu 
1023af24660dSWilly Tu         if (version == nullptr)
1024af24660dSWilly Tu         {
102562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
1026af24660dSWilly Tu 
1027af24660dSWilly Tu             messages::internalError(asyncResp->res);
1028af24660dSWilly Tu 
1029af24660dSWilly Tu             return;
1030af24660dSWilly Tu         }
1031af24660dSWilly Tu         asyncResp->res.jsonValue["Version"] = *version;
1032af24660dSWilly Tu         asyncResp->res.jsonValue["Id"] = swId;
1033af24660dSWilly Tu 
1034af24660dSWilly Tu         // swInvPurpose is of format:
1035af24660dSWilly Tu         // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1036af24660dSWilly Tu         // Translate this to "ABC image"
1037af24660dSWilly Tu         size_t endDesc = swInvPurpose->rfind('.');
1038af24660dSWilly Tu         if (endDesc == std::string::npos)
1039af24660dSWilly Tu         {
1040af24660dSWilly Tu             messages::internalError(asyncResp->res);
1041af24660dSWilly Tu             return;
1042af24660dSWilly Tu         }
1043af24660dSWilly Tu         endDesc++;
1044af24660dSWilly Tu         if (endDesc >= swInvPurpose->size())
1045af24660dSWilly Tu         {
1046af24660dSWilly Tu             messages::internalError(asyncResp->res);
1047af24660dSWilly Tu             return;
1048af24660dSWilly Tu         }
1049af24660dSWilly Tu 
1050af24660dSWilly Tu         std::string formatDesc = swInvPurpose->substr(endDesc);
1051af24660dSWilly Tu         asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1052af24660dSWilly Tu         getRelatedItems(asyncResp, *swInvPurpose);
1053d1bde9e5SKrzysztof Grobelny     });
1054af24660dSWilly Tu }
1055af24660dSWilly Tu 
1056f5139334SEd Tanous inline void handleUpdateServiceFirmwareInventoryGet(
1057f5139334SEd Tanous     App& app, const crow::Request& req,
105845ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1059f5139334SEd Tanous     const std::string& param)
1060f5139334SEd Tanous {
10613ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106245ca1b86SEd Tanous     {
106345ca1b86SEd Tanous         return;
106445ca1b86SEd Tanous     }
1065f5139334SEd Tanous     std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1066c711bf86SEd Tanous 
1067ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1068ef4c65b7SEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1069c711bf86SEd Tanous 
1070e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1071e99073f5SGeorge Liu         "xyz.openbmc_project.Software.Version"};
1072e99073f5SGeorge Liu     dbus::utility::getSubTree(
1073e99073f5SGeorge Liu         "/", 0, interfaces,
1074b9d36b47SEd Tanous         [asyncResp,
1075e99073f5SGeorge Liu          swId](const boost::system::error_code& ec,
1076b9d36b47SEd Tanous                const dbus::utility::MapperGetSubTreeResponse& subtree) {
107762598e31SEd Tanous         BMCWEB_LOG_DEBUG("doGet callback...");
10781abe55efSEd Tanous         if (ec)
10791abe55efSEd Tanous         {
1080f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
10816c4eb9deSJennifer Lee             return;
10826c4eb9deSJennifer Lee         }
10836c4eb9deSJennifer Lee 
10846913228dSAndrew Geissler         // Ensure we find our input swId, otherwise return an error
10856913228dSAndrew Geissler         bool found = false;
1086f5139334SEd Tanous         for (const std::pair<
1087f5139334SEd Tanous                  std::string,
1088f5139334SEd Tanous                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1089002d39b4SEd Tanous                  obj : subtree)
10901abe55efSEd Tanous         {
109111ba3979SEd Tanous             if (!obj.first.ends_with(*swId))
10921abe55efSEd Tanous             {
1093acb7cfb4SJennifer Lee                 continue;
1094acb7cfb4SJennifer Lee             }
1095acb7cfb4SJennifer Lee 
109626f6976fSEd Tanous             if (obj.second.empty())
10971abe55efSEd Tanous             {
1098acb7cfb4SJennifer Lee                 continue;
1099acb7cfb4SJennifer Lee             }
11006c4eb9deSJennifer Lee 
11016913228dSAndrew Geissler             found = true;
1102eee0013eSWilly Tu             sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1103af24660dSWilly Tu             getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1104af24660dSWilly Tu                                *swId);
11056c4eb9deSJennifer Lee         }
11066913228dSAndrew Geissler         if (!found)
11076913228dSAndrew Geissler         {
110862598e31SEd Tanous             BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
11096913228dSAndrew Geissler             messages::resourceMissingAtURI(
1110ef4c65b7SEd Tanous                 asyncResp->res,
1111ef4c65b7SEd Tanous                 boost::urls::format(
1112f5139334SEd Tanous                     "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId));
11136913228dSAndrew Geissler             return;
11146913228dSAndrew Geissler         }
11154e68c45bSAyushi Smriti         asyncResp->res.jsonValue["@odata.type"] =
11164e68c45bSAyushi Smriti             "#SoftwareInventory.v1_1_0.SoftwareInventory";
11174e68c45bSAyushi Smriti         asyncResp->res.jsonValue["Name"] = "Software Inventory";
11184e68c45bSAyushi Smriti         asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
11193f8a743aSAppaRao Puli 
11203f8a743aSAppaRao Puli         asyncResp->res.jsonValue["Updateable"] = false;
1121eee0013eSWilly Tu         sw_util::getSwUpdatableStatus(asyncResp, swId);
1122e99073f5SGeorge Liu     });
1123f5139334SEd Tanous }
1124f5139334SEd Tanous 
1125f5139334SEd Tanous inline void requestRoutesUpdateService(App& app)
1126f5139334SEd Tanous {
1127f5139334SEd Tanous     BMCWEB_ROUTE(
1128f5139334SEd Tanous         app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1129f5139334SEd Tanous         .privileges(redfish::privileges::postUpdateService)
1130f5139334SEd Tanous         .methods(boost::beast::http::verb::post)(std::bind_front(
1131f5139334SEd Tanous             handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1132f5139334SEd Tanous 
1133f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1134f5139334SEd Tanous         .privileges(redfish::privileges::getSoftwareInventory)
1135f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
1136f5139334SEd Tanous             handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1137f5139334SEd Tanous 
1138f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1139f5139334SEd Tanous         .privileges(redfish::privileges::getUpdateService)
1140f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(
1141f5139334SEd Tanous             std::bind_front(handleUpdateServiceGet, std::ref(app)));
1142f5139334SEd Tanous 
1143f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1144f5139334SEd Tanous         .privileges(redfish::privileges::patchUpdateService)
1145f5139334SEd Tanous         .methods(boost::beast::http::verb::patch)(
1146f5139334SEd Tanous             std::bind_front(handleUpdateServicePatch, std::ref(app)));
1147f5139334SEd Tanous 
1148f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1149f5139334SEd Tanous         .privileges(redfish::privileges::postUpdateService)
1150f5139334SEd Tanous         .methods(boost::beast::http::verb::post)(
1151f5139334SEd Tanous             std::bind_front(handleUpdateServicePost, std::ref(app)));
1152f5139334SEd Tanous 
1153f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1154f5139334SEd Tanous         .privileges(redfish::privileges::getSoftwareInventoryCollection)
1155f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
1156f5139334SEd Tanous             handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
11576c4eb9deSJennifer Lee }
1158729dae72SJennifer Lee 
1159729dae72SJennifer Lee } // namespace redfish
1160