xref: /openbmc/bmcweb/features/redfish/lib/virtual_media.hpp (revision 739b87efe5d1065b89c381a68e7e12177f1f5741)
1107077deSPrzemyslaw Czarnowski /*
2107077deSPrzemyslaw Czarnowski // Copyright (c) 2018 Intel Corporation
3107077deSPrzemyslaw Czarnowski //
4107077deSPrzemyslaw Czarnowski // Licensed under the Apache License, Version 2.0 (the "License");
5107077deSPrzemyslaw Czarnowski // you may not use this file except in compliance with the License.
6107077deSPrzemyslaw Czarnowski // You may obtain a copy of the License at
7107077deSPrzemyslaw Czarnowski //
8107077deSPrzemyslaw Czarnowski //      http://www.apache.org/licenses/LICENSE-2.0
9107077deSPrzemyslaw Czarnowski //
10107077deSPrzemyslaw Czarnowski // Unless required by applicable law or agreed to in writing, software
11107077deSPrzemyslaw Czarnowski // distributed under the License is distributed on an "AS IS" BASIS,
12107077deSPrzemyslaw Czarnowski // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13107077deSPrzemyslaw Czarnowski // See the License for the specific language governing permissions and
14107077deSPrzemyslaw Czarnowski // limitations under the License.
15107077deSPrzemyslaw Czarnowski */
16107077deSPrzemyslaw Czarnowski #pragma once
17107077deSPrzemyslaw Czarnowski 
183ccb3adbSEd Tanous #include "account_service.hpp"
193ccb3adbSEd Tanous #include "app.hpp"
202b73119cSGeorge Liu #include "dbus_utility.hpp"
21*739b87efSEd Tanous #include "generated/enums/virtual_media.hpp"
223ccb3adbSEd Tanous #include "query.hpp"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
243ccb3adbSEd Tanous #include "utils/json_utils.hpp"
253ccb3adbSEd Tanous 
26988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp>
27988fb7b2SAdrian Ambrożewicz #include <boost/type_traits/has_dereference.hpp>
289e319cf0SAnna Platash #include <boost/url/url_view.hpp>
29107077deSPrzemyslaw Czarnowski 
302b73119cSGeorge Liu #include <array>
312b73119cSGeorge Liu #include <string_view>
322b73119cSGeorge Liu 
33107077deSPrzemyslaw Czarnowski namespace redfish
34107077deSPrzemyslaw Czarnowski {
35365a73f4SEd Tanous 
36365a73f4SEd Tanous enum class VmMode
37365a73f4SEd Tanous {
38365a73f4SEd Tanous     Invalid,
39365a73f4SEd Tanous     Legacy,
40365a73f4SEd Tanous     Proxy
41365a73f4SEd Tanous };
42365a73f4SEd Tanous 
43365a73f4SEd Tanous inline VmMode
44365a73f4SEd Tanous     parseObjectPathAndGetMode(const sdbusplus::message::object_path& itemPath,
45365a73f4SEd Tanous                               const std::string& resName)
46365a73f4SEd Tanous {
47365a73f4SEd Tanous     std::string thisPath = itemPath.filename();
48365a73f4SEd Tanous     BMCWEB_LOG_DEBUG << "Filename: " << itemPath.str
49365a73f4SEd Tanous                      << ", ThisPath: " << thisPath;
50365a73f4SEd Tanous 
51365a73f4SEd Tanous     if (thisPath.empty())
52365a73f4SEd Tanous     {
53365a73f4SEd Tanous         return VmMode::Invalid;
54365a73f4SEd Tanous     }
55365a73f4SEd Tanous 
56365a73f4SEd Tanous     if (thisPath != resName)
57365a73f4SEd Tanous     {
58365a73f4SEd Tanous         return VmMode::Invalid;
59365a73f4SEd Tanous     }
60365a73f4SEd Tanous 
61365a73f4SEd Tanous     auto mode = itemPath.parent_path();
62365a73f4SEd Tanous     auto type = mode.parent_path();
63365a73f4SEd Tanous 
64365a73f4SEd Tanous     if (mode.filename().empty() || type.filename().empty())
65365a73f4SEd Tanous     {
66365a73f4SEd Tanous         return VmMode::Invalid;
67365a73f4SEd Tanous     }
68365a73f4SEd Tanous 
69365a73f4SEd Tanous     if (type.filename() != "VirtualMedia")
70365a73f4SEd Tanous     {
71365a73f4SEd Tanous         return VmMode::Invalid;
72365a73f4SEd Tanous     }
73365a73f4SEd Tanous     std::string modeStr = mode.filename();
74365a73f4SEd Tanous     if (modeStr == "Legacy")
75365a73f4SEd Tanous     {
76365a73f4SEd Tanous         return VmMode::Legacy;
77365a73f4SEd Tanous     }
78365a73f4SEd Tanous     if (modeStr == "Proxy")
79365a73f4SEd Tanous     {
80365a73f4SEd Tanous         return VmMode::Proxy;
81365a73f4SEd Tanous     }
82365a73f4SEd Tanous     return VmMode::Invalid;
83365a73f4SEd Tanous }
84365a73f4SEd Tanous 
859e319cf0SAnna Platash /**
869e319cf0SAnna Platash  * @brief Function extracts transfer protocol name from URI.
879e319cf0SAnna Platash  */
8867df073bSEd Tanous inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
8967df073bSEd Tanous {
9067df073bSEd Tanous     boost::urls::result<boost::urls::url_view> url =
91079360aeSEd Tanous         boost::urls::parse_uri(imageUri);
9267df073bSEd Tanous     if (!url)
9367df073bSEd Tanous     {
9467df073bSEd Tanous         return "None";
9567df073bSEd Tanous     }
96079360aeSEd Tanous     std::string_view scheme = url->scheme();
9767df073bSEd Tanous     if (scheme == "smb")
9867df073bSEd Tanous     {
9967df073bSEd Tanous         return "CIFS";
10067df073bSEd Tanous     }
10167df073bSEd Tanous     if (scheme == "https")
10267df073bSEd Tanous     {
10367df073bSEd Tanous         return "HTTPS";
10467df073bSEd Tanous     }
10567df073bSEd Tanous 
10667df073bSEd Tanous     return "None";
10767df073bSEd Tanous }
108107077deSPrzemyslaw Czarnowski 
109107077deSPrzemyslaw Czarnowski /**
110107077deSPrzemyslaw Czarnowski  * @brief Read all known properties from VM object interfaces
111107077deSPrzemyslaw Czarnowski  */
11222db1728SEd Tanous inline void
1138a592810SEd Tanous     vmParseInterfaceObject(const dbus::utility::DBusInteracesMap& interfaces,
1148d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& aResp)
115107077deSPrzemyslaw Czarnowski {
1168a592810SEd Tanous     for (const auto& [interface, values] : interfaces)
117107077deSPrzemyslaw Czarnowski     {
118711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.VirtualMedia.MountPoint")
119107077deSPrzemyslaw Czarnowski         {
120711ac7a9SEd Tanous             for (const auto& [property, value] : values)
121107077deSPrzemyslaw Czarnowski             {
122711ac7a9SEd Tanous                 if (property == "EndpointId")
123107077deSPrzemyslaw Czarnowski                 {
124107077deSPrzemyslaw Czarnowski                     const std::string* endpointIdValue =
125711ac7a9SEd Tanous                         std::get_if<std::string>(&value);
126711ac7a9SEd Tanous                     if (endpointIdValue == nullptr)
127107077deSPrzemyslaw Czarnowski                     {
128711ac7a9SEd Tanous                         continue;
129711ac7a9SEd Tanous                     }
130107077deSPrzemyslaw Czarnowski                     if (!endpointIdValue->empty())
131107077deSPrzemyslaw Czarnowski                     {
132107077deSPrzemyslaw Czarnowski                         // Proxy mode
133711ac7a9SEd Tanous                         aResp->res
134711ac7a9SEd Tanous                             .jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
135d04ba325SPrzemyslaw Czarnowski                             *endpointIdValue;
136107077deSPrzemyslaw Czarnowski                         aResp->res.jsonValue["TransferProtocolType"] = "OEM";
137107077deSPrzemyslaw Czarnowski                     }
138107077deSPrzemyslaw Czarnowski                 }
139711ac7a9SEd Tanous                 if (property == "ImageURL")
140107077deSPrzemyslaw Czarnowski                 {
141107077deSPrzemyslaw Czarnowski                     const std::string* imageUrlValue =
142711ac7a9SEd Tanous                         std::get_if<std::string>(&value);
14326f6976fSEd Tanous                     if (imageUrlValue != nullptr && !imageUrlValue->empty())
144107077deSPrzemyslaw Czarnowski                     {
145da4784d8SPrzemyslaw Czarnowski                         std::filesystem::path filePath = *imageUrlValue;
146da4784d8SPrzemyslaw Czarnowski                         if (!filePath.has_filename())
147da4784d8SPrzemyslaw Czarnowski                         {
1489e319cf0SAnna Platash                             // this will handle https share, which not
1499e319cf0SAnna Platash                             // necessarily has to have filename given.
150da4784d8SPrzemyslaw Czarnowski                             aResp->res.jsonValue["ImageName"] = "";
151da4784d8SPrzemyslaw Czarnowski                         }
152da4784d8SPrzemyslaw Czarnowski                         else
153da4784d8SPrzemyslaw Czarnowski                         {
1549e319cf0SAnna Platash                             aResp->res.jsonValue["ImageName"] =
1559e319cf0SAnna Platash                                 filePath.filename();
156da4784d8SPrzemyslaw Czarnowski                         }
157da4784d8SPrzemyslaw Czarnowski 
158da4784d8SPrzemyslaw Czarnowski                         aResp->res.jsonValue["Image"] = *imageUrlValue;
1599e319cf0SAnna Platash                         aResp->res.jsonValue["TransferProtocolType"] =
1609e319cf0SAnna Platash                             getTransferProtocolTypeFromUri(*imageUrlValue);
1619e319cf0SAnna Platash 
162*739b87efSEd Tanous                         aResp->res.jsonValue["ConnectedVia"] =
163*739b87efSEd Tanous                             virtual_media::ConnectedVia::URI;
164107077deSPrzemyslaw Czarnowski                     }
165107077deSPrzemyslaw Czarnowski                 }
166711ac7a9SEd Tanous                 if (property == "WriteProtected")
1679e319cf0SAnna Platash                 {
168711ac7a9SEd Tanous                     const bool* writeProtectedValue = std::get_if<bool>(&value);
169e662eae8SEd Tanous                     if (writeProtectedValue != nullptr)
1709e319cf0SAnna Platash                     {
1719e319cf0SAnna Platash                         aResp->res.jsonValue["WriteProtected"] =
1729e319cf0SAnna Platash                             *writeProtectedValue;
1739e319cf0SAnna Platash                     }
1749e319cf0SAnna Platash                 }
1759e319cf0SAnna Platash             }
176107077deSPrzemyslaw Czarnowski         }
177711ac7a9SEd Tanous         if (interface == "xyz.openbmc_project.VirtualMedia.Process")
178711ac7a9SEd Tanous         {
179711ac7a9SEd Tanous             for (const auto& [property, value] : values)
180711ac7a9SEd Tanous             {
181711ac7a9SEd Tanous                 if (property == "Active")
182711ac7a9SEd Tanous                 {
183711ac7a9SEd Tanous                     const bool* activeValue = std::get_if<bool>(&value);
184e662eae8SEd Tanous                     if (activeValue == nullptr)
185711ac7a9SEd Tanous                     {
186711ac7a9SEd Tanous                         BMCWEB_LOG_DEBUG << "Value Active not found";
187711ac7a9SEd Tanous                         return;
188711ac7a9SEd Tanous                     }
189711ac7a9SEd Tanous                     aResp->res.jsonValue["Inserted"] = *activeValue;
190711ac7a9SEd Tanous 
191e05aec50SEd Tanous                     if (*activeValue)
192711ac7a9SEd Tanous                     {
193*739b87efSEd Tanous                         aResp->res.jsonValue["ConnectedVia"] =
194*739b87efSEd Tanous                             virtual_media::ConnectedVia::Applet;
195711ac7a9SEd Tanous                     }
196711ac7a9SEd Tanous                 }
197711ac7a9SEd Tanous             }
198711ac7a9SEd Tanous         }
199107077deSPrzemyslaw Czarnowski     }
200107077deSPrzemyslaw Czarnowski }
201107077deSPrzemyslaw Czarnowski 
202107077deSPrzemyslaw Czarnowski /**
203107077deSPrzemyslaw Czarnowski  * @brief Fill template for Virtual Media Item.
204107077deSPrzemyslaw Czarnowski  */
20522db1728SEd Tanous inline nlohmann::json vmItemTemplate(const std::string& name,
206107077deSPrzemyslaw Czarnowski                                      const std::string& resName)
207107077deSPrzemyslaw Czarnowski {
208107077deSPrzemyslaw Czarnowski     nlohmann::json item;
209fdb20347SEd Tanous     item["@odata.id"] = crow::utility::urlFromPieces(
210fdb20347SEd Tanous         "redfish", "v1", "Managers", name, "VirtualMedia", resName);
21122db1728SEd Tanous 
212d04ba325SPrzemyslaw Czarnowski     item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
213107077deSPrzemyslaw Czarnowski     item["Name"] = "Virtual Removable Media";
214107077deSPrzemyslaw Czarnowski     item["Id"] = resName;
215107077deSPrzemyslaw Czarnowski     item["WriteProtected"] = true;
216*739b87efSEd Tanous     item["ConnectedVia"] = virtual_media::ConnectedVia::NotConnected;
217613dabeaSEd Tanous     item["MediaTypes"] = nlohmann::json::array_t({"CD", "USBStick"});
218107077deSPrzemyslaw Czarnowski     item["TransferMethod"] = "Stream";
219d04ba325SPrzemyslaw Czarnowski     item["Oem"]["OpenBMC"]["@odata.type"] =
220d04ba325SPrzemyslaw Czarnowski         "#OemVirtualMedia.v1_0_0.VirtualMedia";
221107077deSPrzemyslaw Czarnowski 
222107077deSPrzemyslaw Czarnowski     return item;
223107077deSPrzemyslaw Czarnowski }
224107077deSPrzemyslaw Czarnowski 
225107077deSPrzemyslaw Czarnowski /**
226107077deSPrzemyslaw Czarnowski  *  @brief Fills collection data
227107077deSPrzemyslaw Czarnowski  */
22822db1728SEd Tanous inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
229107077deSPrzemyslaw Czarnowski                               const std::string& service,
230107077deSPrzemyslaw Czarnowski                               const std::string& name)
231107077deSPrzemyslaw Czarnowski {
232107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
233107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
23402cad96eSEd Tanous         [name, aResp{std::move(aResp)}](
2355e7e2dc5SEd Tanous             const boost::system::error_code& ec,
23602cad96eSEd Tanous             const dbus::utility::ManagedObjectType& subtree) {
237107077deSPrzemyslaw Czarnowski         if (ec)
238107077deSPrzemyslaw Czarnowski         {
239107077deSPrzemyslaw Czarnowski             BMCWEB_LOG_DEBUG << "DBUS response error";
240107077deSPrzemyslaw Czarnowski             return;
241107077deSPrzemyslaw Czarnowski         }
242107077deSPrzemyslaw Czarnowski         nlohmann::json& members = aResp->res.jsonValue["Members"];
243107077deSPrzemyslaw Czarnowski         members = nlohmann::json::array();
244107077deSPrzemyslaw Czarnowski 
245107077deSPrzemyslaw Czarnowski         for (const auto& object : subtree)
246107077deSPrzemyslaw Czarnowski         {
247107077deSPrzemyslaw Czarnowski             nlohmann::json item;
2482dfd18efSEd Tanous             std::string path = object.first.filename();
2492dfd18efSEd Tanous             if (path.empty())
250107077deSPrzemyslaw Czarnowski             {
251107077deSPrzemyslaw Czarnowski                 continue;
252107077deSPrzemyslaw Czarnowski             }
253107077deSPrzemyslaw Czarnowski 
254fdb20347SEd Tanous             item["@odata.id"] = crow::utility::urlFromPieces(
255fdb20347SEd Tanous                 "redfish", "v1", "Managers", name, "VirtualMedia", path);
256107077deSPrzemyslaw Czarnowski             members.emplace_back(std::move(item));
257107077deSPrzemyslaw Czarnowski         }
258107077deSPrzemyslaw Czarnowski         aResp->res.jsonValue["Members@odata.count"] = members.size();
259107077deSPrzemyslaw Czarnowski         },
260107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
261107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
262107077deSPrzemyslaw Czarnowski }
263107077deSPrzemyslaw Czarnowski 
264107077deSPrzemyslaw Czarnowski /**
265107077deSPrzemyslaw Czarnowski  *  @brief Fills data for specific resource
266107077deSPrzemyslaw Czarnowski  */
26722db1728SEd Tanous inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
268107077deSPrzemyslaw Czarnowski                       const std::string& service, const std::string& name,
269107077deSPrzemyslaw Czarnowski                       const std::string& resName)
270107077deSPrzemyslaw Czarnowski {
271107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
272107077deSPrzemyslaw Czarnowski 
273107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
274914e2d5dSEd Tanous         [resName, name,
2755e7e2dc5SEd Tanous          aResp](const boost::system::error_code& ec,
276914e2d5dSEd Tanous                 const dbus::utility::ManagedObjectType& subtree) {
277107077deSPrzemyslaw Czarnowski         if (ec)
278107077deSPrzemyslaw Czarnowski         {
279107077deSPrzemyslaw Czarnowski             BMCWEB_LOG_DEBUG << "DBUS response error";
280e13c2760SPrzemyslaw Czarnowski 
281107077deSPrzemyslaw Czarnowski             return;
282107077deSPrzemyslaw Czarnowski         }
283107077deSPrzemyslaw Czarnowski 
284914e2d5dSEd Tanous         for (const auto& item : subtree)
285107077deSPrzemyslaw Czarnowski         {
286365a73f4SEd Tanous             VmMode mode = parseObjectPathAndGetMode(item.first, resName);
287365a73f4SEd Tanous             if (mode == VmMode::Invalid)
2881a6258dcSPrzemyslaw Czarnowski             {
2891a6258dcSPrzemyslaw Czarnowski                 continue;
2901a6258dcSPrzemyslaw Czarnowski             }
2911a6258dcSPrzemyslaw Czarnowski 
292107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue = vmItemTemplate(name, resName);
293107077deSPrzemyslaw Czarnowski 
294e13c2760SPrzemyslaw Czarnowski             // Check if dbus path is Legacy type
295365a73f4SEd Tanous             if (mode == VmMode::Legacy)
296e13c2760SPrzemyslaw Czarnowski             {
297e13c2760SPrzemyslaw Czarnowski                 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
298fdb20347SEd Tanous                                     ["target"] = crow::utility::urlFromPieces(
299fdb20347SEd Tanous                     "redfish", "v1", "Managers", name, "VirtualMedia", resName,
300fdb20347SEd Tanous                     "Actions", "VirtualMedia.InsertMedia");
301e13c2760SPrzemyslaw Czarnowski             }
302e13c2760SPrzemyslaw Czarnowski 
303107077deSPrzemyslaw Czarnowski             vmParseInterfaceObject(item.second, aResp);
304107077deSPrzemyslaw Czarnowski 
305002d39b4SEd Tanous             aResp->res
306002d39b4SEd Tanous                 .jsonValue["Actions"]["#VirtualMedia.EjectMedia"]["target"] =
307fdb20347SEd Tanous                 crow::utility::urlFromPieces("redfish", "v1", "Managers", name,
308fdb20347SEd Tanous                                              "VirtualMedia", resName, "Actions",
309fdb20347SEd Tanous                                              "VirtualMedia.EjectMedia");
310107077deSPrzemyslaw Czarnowski             return;
311107077deSPrzemyslaw Czarnowski         }
312107077deSPrzemyslaw Czarnowski 
313d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(aResp->res, "VirtualMedia", resName);
314107077deSPrzemyslaw Czarnowski         },
315107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
316107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
317107077deSPrzemyslaw Czarnowski }
318107077deSPrzemyslaw Czarnowski 
319e13c2760SPrzemyslaw Czarnowski /**
320c6f4e017SAgata Olender  * @brief Transfer protocols supported for InsertMedia action.
321c6f4e017SAgata Olender  *
322c6f4e017SAgata Olender  */
323c6f4e017SAgata Olender enum class TransferProtocol
324c6f4e017SAgata Olender {
325c6f4e017SAgata Olender     https,
326c6f4e017SAgata Olender     smb,
327c6f4e017SAgata Olender     invalid
328c6f4e017SAgata Olender };
329c6f4e017SAgata Olender 
330c6f4e017SAgata Olender /**
331c6f4e017SAgata Olender  * @brief Function extracts transfer protocol type from URI.
332c6f4e017SAgata Olender  *
333c6f4e017SAgata Olender  */
33467df073bSEd Tanous inline std::optional<TransferProtocol>
335ace85d60SEd Tanous     getTransferProtocolFromUri(const boost::urls::url_view& imageUri)
33667df073bSEd Tanous {
337079360aeSEd Tanous     std::string_view scheme = imageUri.scheme();
33867df073bSEd Tanous     if (scheme == "smb")
33967df073bSEd Tanous     {
34067df073bSEd Tanous         return TransferProtocol::smb;
34167df073bSEd Tanous     }
34267df073bSEd Tanous     if (scheme == "https")
34367df073bSEd Tanous     {
34467df073bSEd Tanous         return TransferProtocol::https;
34567df073bSEd Tanous     }
34667df073bSEd Tanous     if (!scheme.empty())
34767df073bSEd Tanous     {
34867df073bSEd Tanous         return TransferProtocol::invalid;
34967df073bSEd Tanous     }
35067df073bSEd Tanous 
35167df073bSEd Tanous     return {};
35267df073bSEd Tanous }
353c6f4e017SAgata Olender 
354c6f4e017SAgata Olender /**
355c6f4e017SAgata Olender  * @brief Function convert transfer protocol from string param.
356c6f4e017SAgata Olender  *
357c6f4e017SAgata Olender  */
35822db1728SEd Tanous inline std::optional<TransferProtocol> getTransferProtocolFromParam(
359c6f4e017SAgata Olender     const std::optional<std::string>& transferProtocolType)
360c6f4e017SAgata Olender {
361c6f4e017SAgata Olender     if (transferProtocolType == std::nullopt)
362c6f4e017SAgata Olender     {
363c6f4e017SAgata Olender         return {};
364c6f4e017SAgata Olender     }
365c6f4e017SAgata Olender 
366c6f4e017SAgata Olender     if (*transferProtocolType == "CIFS")
367c6f4e017SAgata Olender     {
368c6f4e017SAgata Olender         return TransferProtocol::smb;
369c6f4e017SAgata Olender     }
370c6f4e017SAgata Olender 
371c6f4e017SAgata Olender     if (*transferProtocolType == "HTTPS")
372c6f4e017SAgata Olender     {
373c6f4e017SAgata Olender         return TransferProtocol::https;
374c6f4e017SAgata Olender     }
375c6f4e017SAgata Olender 
376c6f4e017SAgata Olender     return TransferProtocol::invalid;
377c6f4e017SAgata Olender }
378c6f4e017SAgata Olender 
379c6f4e017SAgata Olender /**
380c6f4e017SAgata Olender  * @brief Function extends URI with transfer protocol type.
381c6f4e017SAgata Olender  *
382c6f4e017SAgata Olender  */
38322db1728SEd Tanous inline std::string
384c6f4e017SAgata Olender     getUriWithTransferProtocol(const std::string& imageUri,
385c6f4e017SAgata Olender                                const TransferProtocol& transferProtocol)
386c6f4e017SAgata Olender {
387c6f4e017SAgata Olender     if (transferProtocol == TransferProtocol::smb)
388c6f4e017SAgata Olender     {
389c6f4e017SAgata Olender         return "smb://" + imageUri;
390c6f4e017SAgata Olender     }
391c6f4e017SAgata Olender 
392c6f4e017SAgata Olender     if (transferProtocol == TransferProtocol::https)
393c6f4e017SAgata Olender     {
394c6f4e017SAgata Olender         return "https://" + imageUri;
395c6f4e017SAgata Olender     }
396c6f4e017SAgata Olender 
397c6f4e017SAgata Olender     return imageUri;
398c6f4e017SAgata Olender }
399c6f4e017SAgata Olender 
4001f2a40ceSPrzemyslaw Czarnowski struct InsertMediaActionParams
4011f2a40ceSPrzemyslaw Czarnowski {
402120fa86aSPrzemyslaw Czarnowski     std::optional<std::string> imageUrl;
4031f2a40ceSPrzemyslaw Czarnowski     std::optional<std::string> userName;
4041f2a40ceSPrzemyslaw Czarnowski     std::optional<std::string> password;
4051f2a40ceSPrzemyslaw Czarnowski     std::optional<std::string> transferMethod;
4061f2a40ceSPrzemyslaw Czarnowski     std::optional<std::string> transferProtocolType;
4071f2a40ceSPrzemyslaw Czarnowski     std::optional<bool> writeProtected = true;
4081f2a40ceSPrzemyslaw Czarnowski     std::optional<bool> inserted;
4091f2a40ceSPrzemyslaw Czarnowski };
4101f2a40ceSPrzemyslaw Czarnowski 
4111214b7e7SGunnar Mills template <typename T>
4121214b7e7SGunnar Mills static void secureCleanup(T& value)
413988fb7b2SAdrian Ambrożewicz {
4144ecc618fSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
415988fb7b2SAdrian Ambrożewicz     auto raw = const_cast<typename T::value_type*>(value.data());
416988fb7b2SAdrian Ambrożewicz     explicit_bzero(raw, value.size() * sizeof(*raw));
417988fb7b2SAdrian Ambrożewicz }
418988fb7b2SAdrian Ambrożewicz 
419988fb7b2SAdrian Ambrożewicz class Credentials
420988fb7b2SAdrian Ambrożewicz {
421988fb7b2SAdrian Ambrożewicz   public:
422988fb7b2SAdrian Ambrożewicz     Credentials(std::string&& user, std::string&& password) :
423988fb7b2SAdrian Ambrożewicz         userBuf(std::move(user)), passBuf(std::move(password))
4241214b7e7SGunnar Mills     {}
425988fb7b2SAdrian Ambrożewicz 
426988fb7b2SAdrian Ambrożewicz     ~Credentials()
427988fb7b2SAdrian Ambrożewicz     {
428988fb7b2SAdrian Ambrożewicz         secureCleanup(userBuf);
429988fb7b2SAdrian Ambrożewicz         secureCleanup(passBuf);
430988fb7b2SAdrian Ambrożewicz     }
431988fb7b2SAdrian Ambrożewicz 
432988fb7b2SAdrian Ambrożewicz     const std::string& user()
433988fb7b2SAdrian Ambrożewicz     {
434988fb7b2SAdrian Ambrożewicz         return userBuf;
435988fb7b2SAdrian Ambrożewicz     }
436988fb7b2SAdrian Ambrożewicz 
437988fb7b2SAdrian Ambrożewicz     const std::string& password()
438988fb7b2SAdrian Ambrożewicz     {
439988fb7b2SAdrian Ambrożewicz         return passBuf;
440988fb7b2SAdrian Ambrożewicz     }
441988fb7b2SAdrian Ambrożewicz 
442988fb7b2SAdrian Ambrożewicz     Credentials() = delete;
443988fb7b2SAdrian Ambrożewicz     Credentials(const Credentials&) = delete;
444988fb7b2SAdrian Ambrożewicz     Credentials& operator=(const Credentials&) = delete;
445ecd6a3a2SEd Tanous     Credentials(Credentials&&) = delete;
446ecd6a3a2SEd Tanous     Credentials& operator=(Credentials&&) = delete;
447988fb7b2SAdrian Ambrożewicz 
44822db1728SEd Tanous   private:
449988fb7b2SAdrian Ambrożewicz     std::string userBuf;
450988fb7b2SAdrian Ambrożewicz     std::string passBuf;
451988fb7b2SAdrian Ambrożewicz };
452988fb7b2SAdrian Ambrożewicz 
453988fb7b2SAdrian Ambrożewicz class CredentialsProvider
454988fb7b2SAdrian Ambrożewicz {
455988fb7b2SAdrian Ambrożewicz   public:
4561214b7e7SGunnar Mills     template <typename T>
4571214b7e7SGunnar Mills     struct Deleter
458988fb7b2SAdrian Ambrożewicz     {
459988fb7b2SAdrian Ambrożewicz         void operator()(T* buff) const
460988fb7b2SAdrian Ambrożewicz         {
461988fb7b2SAdrian Ambrożewicz             if (buff)
462988fb7b2SAdrian Ambrożewicz             {
463988fb7b2SAdrian Ambrożewicz                 secureCleanup(*buff);
464988fb7b2SAdrian Ambrożewicz                 delete buff;
465988fb7b2SAdrian Ambrożewicz             }
466988fb7b2SAdrian Ambrożewicz         }
467988fb7b2SAdrian Ambrożewicz     };
468988fb7b2SAdrian Ambrożewicz 
469988fb7b2SAdrian Ambrożewicz     using Buffer = std::vector<char>;
470988fb7b2SAdrian Ambrożewicz     using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
471988fb7b2SAdrian Ambrożewicz     // Using explicit definition instead of std::function to avoid implicit
472988fb7b2SAdrian Ambrożewicz     // conversions eg. stack copy instead of reference
473988fb7b2SAdrian Ambrożewicz     using FormatterFunc = void(const std::string& username,
474988fb7b2SAdrian Ambrożewicz                                const std::string& password, Buffer& dest);
475988fb7b2SAdrian Ambrożewicz 
476988fb7b2SAdrian Ambrożewicz     CredentialsProvider(std::string&& user, std::string&& password) :
477988fb7b2SAdrian Ambrożewicz         credentials(std::move(user), std::move(password))
4781214b7e7SGunnar Mills     {}
479988fb7b2SAdrian Ambrożewicz 
480988fb7b2SAdrian Ambrożewicz     const std::string& user()
481988fb7b2SAdrian Ambrożewicz     {
482988fb7b2SAdrian Ambrożewicz         return credentials.user();
483988fb7b2SAdrian Ambrożewicz     }
484988fb7b2SAdrian Ambrożewicz 
485988fb7b2SAdrian Ambrożewicz     const std::string& password()
486988fb7b2SAdrian Ambrożewicz     {
487988fb7b2SAdrian Ambrożewicz         return credentials.password();
488988fb7b2SAdrian Ambrożewicz     }
489988fb7b2SAdrian Ambrożewicz 
4901917ee95SEd Tanous     SecureBuffer pack(FormatterFunc* formatter)
491988fb7b2SAdrian Ambrożewicz     {
492988fb7b2SAdrian Ambrożewicz         SecureBuffer packed{new Buffer{}};
493e662eae8SEd Tanous         if (formatter != nullptr)
494988fb7b2SAdrian Ambrożewicz         {
495988fb7b2SAdrian Ambrożewicz             formatter(credentials.user(), credentials.password(), *packed);
496988fb7b2SAdrian Ambrożewicz         }
497988fb7b2SAdrian Ambrożewicz 
498988fb7b2SAdrian Ambrożewicz         return packed;
499988fb7b2SAdrian Ambrożewicz     }
500988fb7b2SAdrian Ambrożewicz 
501988fb7b2SAdrian Ambrożewicz   private:
502988fb7b2SAdrian Ambrożewicz     Credentials credentials;
503988fb7b2SAdrian Ambrożewicz };
504988fb7b2SAdrian Ambrożewicz 
505988fb7b2SAdrian Ambrożewicz // Wrapper for boost::async_pipe ensuring proper pipe cleanup
5061214b7e7SGunnar Mills template <typename Buffer>
5071214b7e7SGunnar Mills class Pipe
508988fb7b2SAdrian Ambrożewicz {
509988fb7b2SAdrian Ambrożewicz   public:
510988fb7b2SAdrian Ambrożewicz     using unix_fd = sdbusplus::message::unix_fd;
511988fb7b2SAdrian Ambrożewicz 
5128a592810SEd Tanous     Pipe(boost::asio::io_context& io, Buffer&& bufferIn) :
5138a592810SEd Tanous         impl(io), buffer{std::move(bufferIn)}
5141214b7e7SGunnar Mills     {}
515988fb7b2SAdrian Ambrożewicz 
516988fb7b2SAdrian Ambrożewicz     ~Pipe()
517988fb7b2SAdrian Ambrożewicz     {
518988fb7b2SAdrian Ambrożewicz         // Named pipe needs to be explicitly removed
519988fb7b2SAdrian Ambrożewicz         impl.close();
520988fb7b2SAdrian Ambrożewicz     }
521988fb7b2SAdrian Ambrożewicz 
522ecd6a3a2SEd Tanous     Pipe(const Pipe&) = delete;
523ecd6a3a2SEd Tanous     Pipe(Pipe&&) = delete;
524ecd6a3a2SEd Tanous     Pipe& operator=(const Pipe&) = delete;
525ecd6a3a2SEd Tanous     Pipe& operator=(Pipe&&) = delete;
526ecd6a3a2SEd Tanous 
527988fb7b2SAdrian Ambrożewicz     unix_fd fd()
528988fb7b2SAdrian Ambrożewicz     {
529988fb7b2SAdrian Ambrożewicz         return unix_fd{impl.native_source()};
530988fb7b2SAdrian Ambrożewicz     }
531988fb7b2SAdrian Ambrożewicz 
532988fb7b2SAdrian Ambrożewicz     template <typename WriteHandler>
53381ce609eSEd Tanous     void asyncWrite(WriteHandler&& handler)
534988fb7b2SAdrian Ambrożewicz     {
535988fb7b2SAdrian Ambrożewicz         impl.async_write_some(data(), std::forward<WriteHandler>(handler));
536988fb7b2SAdrian Ambrożewicz     }
537988fb7b2SAdrian Ambrożewicz 
538988fb7b2SAdrian Ambrożewicz   private:
539988fb7b2SAdrian Ambrożewicz     // Specialization for pointer types
540988fb7b2SAdrian Ambrożewicz     template <typename B = Buffer>
541988fb7b2SAdrian Ambrożewicz     typename std::enable_if<boost::has_dereference<B>::value,
542988fb7b2SAdrian Ambrożewicz                             boost::asio::const_buffer>::type
543988fb7b2SAdrian Ambrożewicz         data()
544988fb7b2SAdrian Ambrożewicz     {
545988fb7b2SAdrian Ambrożewicz         return boost::asio::buffer(*buffer);
546988fb7b2SAdrian Ambrożewicz     }
547988fb7b2SAdrian Ambrożewicz 
548988fb7b2SAdrian Ambrożewicz     template <typename B = Buffer>
549988fb7b2SAdrian Ambrożewicz     typename std::enable_if<!boost::has_dereference<B>::value,
550988fb7b2SAdrian Ambrożewicz                             boost::asio::const_buffer>::type
551988fb7b2SAdrian Ambrożewicz         data()
552988fb7b2SAdrian Ambrożewicz     {
553988fb7b2SAdrian Ambrożewicz         return boost::asio::buffer(buffer);
554988fb7b2SAdrian Ambrożewicz     }
555988fb7b2SAdrian Ambrożewicz 
556988fb7b2SAdrian Ambrożewicz     const std::string name;
557988fb7b2SAdrian Ambrożewicz     boost::process::async_pipe impl;
558988fb7b2SAdrian Ambrożewicz     Buffer buffer;
559988fb7b2SAdrian Ambrożewicz };
560988fb7b2SAdrian Ambrożewicz 
561e13c2760SPrzemyslaw Czarnowski /**
562e13c2760SPrzemyslaw Czarnowski  * @brief Function transceives data with dbus directly.
563e13c2760SPrzemyslaw Czarnowski  *
564e13c2760SPrzemyslaw Czarnowski  * All BMC state properties will be retrieved before sending reset request.
565e13c2760SPrzemyslaw Czarnowski  */
56622db1728SEd Tanous inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567e13c2760SPrzemyslaw Czarnowski                             const std::string& service, const std::string& name,
568988fb7b2SAdrian Ambrożewicz                             const std::string& imageUrl, const bool rw,
569988fb7b2SAdrian Ambrożewicz                             std::string&& userName, std::string&& password)
570e13c2760SPrzemyslaw Czarnowski {
571988fb7b2SAdrian Ambrożewicz     using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
572988fb7b2SAdrian Ambrożewicz     constexpr const size_t secretLimit = 1024;
573988fb7b2SAdrian Ambrożewicz 
574988fb7b2SAdrian Ambrożewicz     std::shared_ptr<SecurePipe> secretPipe;
575168e20c1SEd Tanous     dbus::utility::DbusVariantType unixFd = -1;
576988fb7b2SAdrian Ambrożewicz 
577988fb7b2SAdrian Ambrożewicz     if (!userName.empty() || !password.empty())
578988fb7b2SAdrian Ambrożewicz     {
579988fb7b2SAdrian Ambrożewicz         // Encapsulate in safe buffer
580988fb7b2SAdrian Ambrożewicz         CredentialsProvider credentials(std::move(userName),
581988fb7b2SAdrian Ambrożewicz                                         std::move(password));
582988fb7b2SAdrian Ambrożewicz 
583988fb7b2SAdrian Ambrożewicz         // Payload must contain data + NULL delimiters
584988fb7b2SAdrian Ambrożewicz         if (credentials.user().size() + credentials.password().size() + 2 >
585988fb7b2SAdrian Ambrożewicz             secretLimit)
586988fb7b2SAdrian Ambrożewicz         {
587988fb7b2SAdrian Ambrożewicz             BMCWEB_LOG_ERROR << "Credentials too long to handle";
588988fb7b2SAdrian Ambrożewicz             messages::unrecognizedRequestBody(asyncResp->res);
589988fb7b2SAdrian Ambrożewicz             return;
590988fb7b2SAdrian Ambrożewicz         }
591988fb7b2SAdrian Ambrożewicz 
592988fb7b2SAdrian Ambrożewicz         // Pack secret
59322db1728SEd Tanous         auto secret = credentials.pack(
59422db1728SEd Tanous             [](const auto& user, const auto& pass, auto& buff) {
595988fb7b2SAdrian Ambrożewicz             std::copy(user.begin(), user.end(), std::back_inserter(buff));
596988fb7b2SAdrian Ambrożewicz             buff.push_back('\0');
597988fb7b2SAdrian Ambrożewicz             std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
598988fb7b2SAdrian Ambrożewicz             buff.push_back('\0');
599988fb7b2SAdrian Ambrożewicz         });
600988fb7b2SAdrian Ambrożewicz 
601988fb7b2SAdrian Ambrożewicz         // Open pipe
602988fb7b2SAdrian Ambrożewicz         secretPipe = std::make_shared<SecurePipe>(
60322db1728SEd Tanous             crow::connections::systemBus->get_io_context(), std::move(secret));
604988fb7b2SAdrian Ambrożewicz         unixFd = secretPipe->fd();
605988fb7b2SAdrian Ambrożewicz 
606988fb7b2SAdrian Ambrożewicz         // Pass secret over pipe
60781ce609eSEd Tanous         secretPipe->asyncWrite(
608f5b16f03SVikram Bodireddy             [asyncResp](const boost::system::error_code& ec, std::size_t) {
609988fb7b2SAdrian Ambrożewicz             if (ec)
610988fb7b2SAdrian Ambrożewicz             {
611988fb7b2SAdrian Ambrożewicz                 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
612988fb7b2SAdrian Ambrożewicz                 messages::internalError(asyncResp->res);
613988fb7b2SAdrian Ambrożewicz             }
614988fb7b2SAdrian Ambrożewicz         });
615988fb7b2SAdrian Ambrożewicz     }
616988fb7b2SAdrian Ambrożewicz 
617e13c2760SPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
6185e7e2dc5SEd Tanous         [asyncResp, secretPipe](const boost::system::error_code& ec,
619988fb7b2SAdrian Ambrożewicz                                 bool success) {
620e13c2760SPrzemyslaw Czarnowski         if (ec)
621e13c2760SPrzemyslaw Czarnowski         {
622e13c2760SPrzemyslaw Czarnowski             BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
623e13c2760SPrzemyslaw Czarnowski             messages::internalError(asyncResp->res);
624d6da5bebSAdrian Ambrożewicz         }
625d6da5bebSAdrian Ambrożewicz         else if (!success)
626d6da5bebSAdrian Ambrożewicz         {
627d6da5bebSAdrian Ambrożewicz             BMCWEB_LOG_ERROR << "Service responded with error";
628d6da5bebSAdrian Ambrożewicz             messages::generalError(asyncResp->res);
629e13c2760SPrzemyslaw Czarnowski         }
630e13c2760SPrzemyslaw Czarnowski         },
631e13c2760SPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
632988fb7b2SAdrian Ambrożewicz         "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
633988fb7b2SAdrian Ambrożewicz         unixFd);
634e13c2760SPrzemyslaw Czarnowski }
635e13c2760SPrzemyslaw Czarnowski 
636e13c2760SPrzemyslaw Czarnowski /**
637120fa86aSPrzemyslaw Czarnowski  * @brief Function validate parameters of insert media request.
638120fa86aSPrzemyslaw Czarnowski  *
639120fa86aSPrzemyslaw Czarnowski  */
640120fa86aSPrzemyslaw Czarnowski inline void validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
641120fa86aSPrzemyslaw Czarnowski                            const std::string& service,
642120fa86aSPrzemyslaw Czarnowski                            const std::string& resName,
643120fa86aSPrzemyslaw Czarnowski                            InsertMediaActionParams& actionParams)
644120fa86aSPrzemyslaw Czarnowski {
645120fa86aSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Validation started";
646120fa86aSPrzemyslaw Czarnowski     // required param imageUrl must not be empty
647120fa86aSPrzemyslaw Czarnowski     if (!actionParams.imageUrl)
648120fa86aSPrzemyslaw Czarnowski     {
649120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
650120fa86aSPrzemyslaw Czarnowski 
651120fa86aSPrzemyslaw Czarnowski         messages::propertyValueFormatError(asyncResp->res, "<empty>", "Image");
652120fa86aSPrzemyslaw Czarnowski 
653120fa86aSPrzemyslaw Czarnowski         return;
654120fa86aSPrzemyslaw Czarnowski     }
655120fa86aSPrzemyslaw Czarnowski 
656120fa86aSPrzemyslaw Czarnowski     // optional param inserted must be true
657120fa86aSPrzemyslaw Czarnowski     if ((actionParams.inserted != std::nullopt) && !*actionParams.inserted)
658120fa86aSPrzemyslaw Czarnowski     {
659120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR
660120fa86aSPrzemyslaw Czarnowski             << "Request action optional parameter Inserted must be true.";
661120fa86aSPrzemyslaw Czarnowski 
662120fa86aSPrzemyslaw Czarnowski         messages::actionParameterNotSupported(asyncResp->res, "Inserted",
663120fa86aSPrzemyslaw Czarnowski                                               "InsertMedia");
664120fa86aSPrzemyslaw Czarnowski 
665120fa86aSPrzemyslaw Czarnowski         return;
666120fa86aSPrzemyslaw Czarnowski     }
667120fa86aSPrzemyslaw Czarnowski 
668120fa86aSPrzemyslaw Czarnowski     // optional param transferMethod must be stream
669120fa86aSPrzemyslaw Czarnowski     if ((actionParams.transferMethod != std::nullopt) &&
670120fa86aSPrzemyslaw Czarnowski         (*actionParams.transferMethod != "Stream"))
671120fa86aSPrzemyslaw Czarnowski     {
672120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR << "Request action optional parameter "
673120fa86aSPrzemyslaw Czarnowski                             "TransferMethod must be Stream.";
674120fa86aSPrzemyslaw Czarnowski 
675120fa86aSPrzemyslaw Czarnowski         messages::actionParameterNotSupported(asyncResp->res, "TransferMethod",
676120fa86aSPrzemyslaw Czarnowski                                               "InsertMedia");
677120fa86aSPrzemyslaw Czarnowski 
678120fa86aSPrzemyslaw Czarnowski         return;
679120fa86aSPrzemyslaw Czarnowski     }
680120fa86aSPrzemyslaw Czarnowski     boost::urls::result<boost::urls::url_view> url =
681120fa86aSPrzemyslaw Czarnowski         boost::urls::parse_uri(*actionParams.imageUrl);
682120fa86aSPrzemyslaw Czarnowski     if (!url)
683120fa86aSPrzemyslaw Czarnowski     {
684120fa86aSPrzemyslaw Czarnowski         messages::actionParameterValueFormatError(
685120fa86aSPrzemyslaw Czarnowski             asyncResp->res, *actionParams.imageUrl, "Image", "InsertMedia");
686120fa86aSPrzemyslaw Czarnowski         return;
687120fa86aSPrzemyslaw Czarnowski     }
688120fa86aSPrzemyslaw Czarnowski     std::optional<TransferProtocol> uriTransferProtocolType =
689120fa86aSPrzemyslaw Czarnowski         getTransferProtocolFromUri(*url);
690120fa86aSPrzemyslaw Czarnowski 
691120fa86aSPrzemyslaw Czarnowski     std::optional<TransferProtocol> paramTransferProtocolType =
692120fa86aSPrzemyslaw Czarnowski         getTransferProtocolFromParam(actionParams.transferProtocolType);
693120fa86aSPrzemyslaw Czarnowski 
694120fa86aSPrzemyslaw Czarnowski     // ImageUrl does not contain valid protocol type
695120fa86aSPrzemyslaw Czarnowski     if (*uriTransferProtocolType == TransferProtocol::invalid)
696120fa86aSPrzemyslaw Czarnowski     {
697120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
698120fa86aSPrzemyslaw Czarnowski                             "contain specified protocol type from list: "
699120fa86aSPrzemyslaw Czarnowski                             "(smb, https).";
700120fa86aSPrzemyslaw Czarnowski 
701120fa86aSPrzemyslaw Czarnowski         messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
702120fa86aSPrzemyslaw Czarnowski 
703120fa86aSPrzemyslaw Czarnowski         return;
704120fa86aSPrzemyslaw Czarnowski     }
705120fa86aSPrzemyslaw Czarnowski 
706120fa86aSPrzemyslaw Czarnowski     // transferProtocolType should contain value from list
707120fa86aSPrzemyslaw Czarnowski     if (*paramTransferProtocolType == TransferProtocol::invalid)
708120fa86aSPrzemyslaw Czarnowski     {
709120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
710120fa86aSPrzemyslaw Czarnowski                             "must be provided with value from list: "
711120fa86aSPrzemyslaw Czarnowski                             "(CIFS, HTTPS).";
712120fa86aSPrzemyslaw Czarnowski 
713120fa86aSPrzemyslaw Czarnowski         messages::propertyValueNotInList(asyncResp->res,
714120fa86aSPrzemyslaw Czarnowski                                          *actionParams.transferProtocolType,
715120fa86aSPrzemyslaw Czarnowski                                          "TransferProtocolType");
716120fa86aSPrzemyslaw Czarnowski         return;
717120fa86aSPrzemyslaw Czarnowski     }
718120fa86aSPrzemyslaw Czarnowski 
719120fa86aSPrzemyslaw Czarnowski     // valid transfer protocol not provided either with URI nor param
720120fa86aSPrzemyslaw Czarnowski     if ((uriTransferProtocolType == std::nullopt) &&
721120fa86aSPrzemyslaw Czarnowski         (paramTransferProtocolType == std::nullopt))
722120fa86aSPrzemyslaw Czarnowski     {
723120fa86aSPrzemyslaw Czarnowski         BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
724120fa86aSPrzemyslaw Czarnowski                             "contain specified protocol type or param "
725120fa86aSPrzemyslaw Czarnowski                             "TransferProtocolType must be provided.";
726120fa86aSPrzemyslaw Czarnowski 
727120fa86aSPrzemyslaw Czarnowski         messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
728120fa86aSPrzemyslaw Czarnowski 
729120fa86aSPrzemyslaw Czarnowski         return;
730120fa86aSPrzemyslaw Czarnowski     }
731120fa86aSPrzemyslaw Czarnowski 
732120fa86aSPrzemyslaw Czarnowski     // valid transfer protocol provided both with URI and param
733120fa86aSPrzemyslaw Czarnowski     if ((paramTransferProtocolType != std::nullopt) &&
734120fa86aSPrzemyslaw Czarnowski         (uriTransferProtocolType != std::nullopt))
735120fa86aSPrzemyslaw Czarnowski     {
736120fa86aSPrzemyslaw Czarnowski         // check if protocol is the same for URI and param
737120fa86aSPrzemyslaw Czarnowski         if (*paramTransferProtocolType != *uriTransferProtocolType)
738120fa86aSPrzemyslaw Czarnowski         {
739120fa86aSPrzemyslaw Czarnowski             BMCWEB_LOG_ERROR << "Request action parameter "
740120fa86aSPrzemyslaw Czarnowski                                 "TransferProtocolType must  contain the "
741120fa86aSPrzemyslaw Czarnowski                                 "same protocol type as protocol type "
742120fa86aSPrzemyslaw Czarnowski                                 "provided with param imageUrl.";
743120fa86aSPrzemyslaw Czarnowski 
744120fa86aSPrzemyslaw Czarnowski             messages::actionParameterValueTypeError(
745120fa86aSPrzemyslaw Czarnowski                 asyncResp->res, *actionParams.transferProtocolType,
746120fa86aSPrzemyslaw Czarnowski                 "TransferProtocolType", "InsertMedia");
747120fa86aSPrzemyslaw Czarnowski 
748120fa86aSPrzemyslaw Czarnowski             return;
749120fa86aSPrzemyslaw Czarnowski         }
750120fa86aSPrzemyslaw Czarnowski     }
751120fa86aSPrzemyslaw Czarnowski 
752120fa86aSPrzemyslaw Czarnowski     // validation passed, add protocol to URI if needed
753120fa86aSPrzemyslaw Czarnowski     if (uriTransferProtocolType == std::nullopt)
754120fa86aSPrzemyslaw Czarnowski     {
755120fa86aSPrzemyslaw Czarnowski         actionParams.imageUrl = getUriWithTransferProtocol(
756120fa86aSPrzemyslaw Czarnowski             *actionParams.imageUrl, *paramTransferProtocolType);
757120fa86aSPrzemyslaw Czarnowski     }
758120fa86aSPrzemyslaw Czarnowski 
759120fa86aSPrzemyslaw Czarnowski     doMountVmLegacy(asyncResp, service, resName, *actionParams.imageUrl,
760120fa86aSPrzemyslaw Czarnowski                     !(*actionParams.writeProtected),
761120fa86aSPrzemyslaw Czarnowski                     std::move(*actionParams.userName),
762120fa86aSPrzemyslaw Czarnowski                     std::move(*actionParams.password));
763120fa86aSPrzemyslaw Czarnowski }
764120fa86aSPrzemyslaw Czarnowski 
765120fa86aSPrzemyslaw Czarnowski /**
766e13c2760SPrzemyslaw Czarnowski  * @brief Function transceives data with dbus directly.
767e13c2760SPrzemyslaw Czarnowski  *
768e13c2760SPrzemyslaw Czarnowski  * All BMC state properties will be retrieved before sending reset request.
769e13c2760SPrzemyslaw Czarnowski  */
77024e740a7SEd Tanous inline void doEjectAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
771e13c2760SPrzemyslaw Czarnowski                           const std::string& service, const std::string& name,
772e13c2760SPrzemyslaw Czarnowski                           bool legacy)
773e13c2760SPrzemyslaw Czarnowski {
774e13c2760SPrzemyslaw Czarnowski 
775e13c2760SPrzemyslaw Czarnowski     // Legacy mount requires parameter with image
776e13c2760SPrzemyslaw Czarnowski     if (legacy)
777e13c2760SPrzemyslaw Czarnowski     {
778e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
7795e7e2dc5SEd Tanous             [asyncResp](const boost::system::error_code& ec) {
780e13c2760SPrzemyslaw Czarnowski             if (ec)
781e13c2760SPrzemyslaw Czarnowski             {
782e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
783e13c2760SPrzemyslaw Czarnowski 
784e13c2760SPrzemyslaw Czarnowski                 messages::internalError(asyncResp->res);
785e13c2760SPrzemyslaw Czarnowski                 return;
786e13c2760SPrzemyslaw Czarnowski             }
787e13c2760SPrzemyslaw Czarnowski             },
788e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
789e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
790e13c2760SPrzemyslaw Czarnowski     }
791e13c2760SPrzemyslaw Czarnowski     else // proxy
792e13c2760SPrzemyslaw Czarnowski     {
793e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
7945e7e2dc5SEd Tanous             [asyncResp](const boost::system::error_code& ec) {
795e13c2760SPrzemyslaw Czarnowski             if (ec)
796e13c2760SPrzemyslaw Czarnowski             {
797e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
798e13c2760SPrzemyslaw Czarnowski 
799e13c2760SPrzemyslaw Czarnowski                 messages::internalError(asyncResp->res);
800e13c2760SPrzemyslaw Czarnowski                 return;
801e13c2760SPrzemyslaw Czarnowski             }
802e13c2760SPrzemyslaw Czarnowski             },
803e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
804e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
805e13c2760SPrzemyslaw Czarnowski     }
806e13c2760SPrzemyslaw Czarnowski }
807e13c2760SPrzemyslaw Czarnowski 
80896825bebSEd Tanous inline void handleManagersVirtualMediaActionInsertPost(
80996825bebSEd Tanous     crow::App& app, const crow::Request& req,
81022db1728SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
81196825bebSEd Tanous     const std::string& name, const std::string& resName)
81296825bebSEd Tanous {
8133ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
81445ca1b86SEd Tanous     {
81545ca1b86SEd Tanous         return;
81645ca1b86SEd Tanous     }
81722db1728SEd Tanous     if (name != "bmc")
818107077deSPrzemyslaw Czarnowski     {
8191f2a40ceSPrzemyslaw Czarnowski         messages::resourceNotFound(asyncResp->res, "VirtualMedia.InsertMedia",
820002d39b4SEd Tanous                                    resName);
821107077deSPrzemyslaw Czarnowski 
822107077deSPrzemyslaw Czarnowski         return;
823107077deSPrzemyslaw Czarnowski     }
824120fa86aSPrzemyslaw Czarnowski     std::optional<InsertMediaActionParams> actionParams =
825120fa86aSPrzemyslaw Czarnowski         InsertMediaActionParams();
82698be3e39SEd Tanous 
827120fa86aSPrzemyslaw Czarnowski     // Read obligatory parameters (url of image)
82815ed6780SWilly Tu     if (!json_util::readJsonAction(
829120fa86aSPrzemyslaw Czarnowski             req, asyncResp->res, "Image", actionParams->imageUrl,
830120fa86aSPrzemyslaw Czarnowski             "WriteProtected", actionParams->writeProtected, "UserName",
831120fa86aSPrzemyslaw Czarnowski             actionParams->userName, "Password", actionParams->password,
832120fa86aSPrzemyslaw Czarnowski             "Inserted", actionParams->inserted, "TransferMethod",
833120fa86aSPrzemyslaw Czarnowski             actionParams->transferMethod, "TransferProtocolType",
834120fa86aSPrzemyslaw Czarnowski             actionParams->transferProtocolType))
83598be3e39SEd Tanous     {
83698be3e39SEd Tanous         return;
83798be3e39SEd Tanous     }
838107077deSPrzemyslaw Czarnowski 
8392b73119cSGeorge Liu     dbus::utility::getDbusObject(
8402b73119cSGeorge Liu         "/xyz/openbmc_project/VirtualMedia", {},
84196825bebSEd Tanous         [asyncResp, actionParams,
8422b73119cSGeorge Liu          resName](const boost::system::error_code& ec,
843002d39b4SEd Tanous                   const dbus::utility::MapperGetObject& getObjectType) mutable {
84422db1728SEd Tanous         if (ec)
84522db1728SEd Tanous         {
84696825bebSEd Tanous             BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " << ec;
84722db1728SEd Tanous             messages::internalError(asyncResp->res);
848107077deSPrzemyslaw Czarnowski 
84922db1728SEd Tanous             return;
85022db1728SEd Tanous         }
85122db1728SEd Tanous         std::string service = getObjectType.begin()->first;
85222db1728SEd Tanous         BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
85322db1728SEd Tanous 
85422db1728SEd Tanous         crow::connections::systemBus->async_method_call(
85598be3e39SEd Tanous             [service, resName, actionParams,
8565e7e2dc5SEd Tanous              asyncResp](const boost::system::error_code& ec2,
857002d39b4SEd Tanous                         dbus::utility::ManagedObjectType& subtree) mutable {
8588a592810SEd Tanous             if (ec2)
85922db1728SEd Tanous             {
86022db1728SEd Tanous                 BMCWEB_LOG_DEBUG << "DBUS response error";
8611f2a40ceSPrzemyslaw Czarnowski                 messages::internalError(asyncResp->res);
86222db1728SEd Tanous 
86322db1728SEd Tanous                 return;
86422db1728SEd Tanous             }
86522db1728SEd Tanous 
86622db1728SEd Tanous             for (const auto& object : subtree)
86722db1728SEd Tanous             {
868365a73f4SEd Tanous                 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
869365a73f4SEd Tanous                 if (mode == VmMode::Proxy)
87022db1728SEd Tanous                 {
871120fa86aSPrzemyslaw Czarnowski                     validateParams(asyncResp, service, resName, *actionParams);
87222db1728SEd Tanous 
87322db1728SEd Tanous                     return;
87422db1728SEd Tanous                 }
87522db1728SEd Tanous             }
87622db1728SEd Tanous             BMCWEB_LOG_DEBUG << "Parent item not found";
87796825bebSEd Tanous             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
87822db1728SEd Tanous             },
87922db1728SEd Tanous             service, "/xyz/openbmc_project/VirtualMedia",
880002d39b4SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8812b73119cSGeorge Liu         });
88296825bebSEd Tanous }
88322db1728SEd Tanous 
88496825bebSEd Tanous inline void handleManagersVirtualMediaActionEject(
88596825bebSEd Tanous     crow::App& app, const crow::Request& req,
88622db1728SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
88796825bebSEd Tanous     const std::string& managerName, const std::string& resName)
88896825bebSEd Tanous {
8893ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
89045ca1b86SEd Tanous     {
89145ca1b86SEd Tanous         return;
89245ca1b86SEd Tanous     }
89396825bebSEd Tanous     if (managerName != "bmc")
894107077deSPrzemyslaw Czarnowski     {
895120fa86aSPrzemyslaw Czarnowski         messages::resourceNotFound(asyncResp->res, "VirtualMedia.EjectMedia",
896002d39b4SEd Tanous                                    resName);
89722db1728SEd Tanous 
89822db1728SEd Tanous         return;
89922db1728SEd Tanous     }
90022db1728SEd Tanous 
9012b73119cSGeorge Liu     dbus::utility::getDbusObject(
9022b73119cSGeorge Liu         "/xyz/openbmc_project/VirtualMedia", {},
903002d39b4SEd Tanous         [asyncResp,
9042b73119cSGeorge Liu          resName](const boost::system::error_code& ec2,
905b9d36b47SEd Tanous                   const dbus::utility::MapperGetObject& getObjectType) {
9068a592810SEd Tanous         if (ec2)
90722db1728SEd Tanous         {
9088a592810SEd Tanous             BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " << ec2;
90922db1728SEd Tanous             messages::internalError(asyncResp->res);
91022db1728SEd Tanous 
91122db1728SEd Tanous             return;
91222db1728SEd Tanous         }
91322db1728SEd Tanous         std::string service = getObjectType.begin()->first;
91422db1728SEd Tanous         BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
91522db1728SEd Tanous 
91622db1728SEd Tanous         crow::connections::systemBus->async_method_call(
91702cad96eSEd Tanous             [resName, service, asyncResp{asyncResp}](
9185e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
91902cad96eSEd Tanous                 const dbus::utility::ManagedObjectType& subtree) {
92022db1728SEd Tanous             if (ec)
92122db1728SEd Tanous             {
92222db1728SEd Tanous                 BMCWEB_LOG_DEBUG << "DBUS response error";
9231f2a40ceSPrzemyslaw Czarnowski                 messages::internalError(asyncResp->res);
92422db1728SEd Tanous 
92522db1728SEd Tanous                 return;
92622db1728SEd Tanous             }
92722db1728SEd Tanous 
92822db1728SEd Tanous             for (const auto& object : subtree)
92922db1728SEd Tanous             {
93022db1728SEd Tanous 
931365a73f4SEd Tanous                 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
932365a73f4SEd Tanous                 if (mode != VmMode::Invalid)
93322db1728SEd Tanous                 {
934365a73f4SEd Tanous                     doEjectAction(asyncResp, service, resName,
935365a73f4SEd Tanous                                   mode == VmMode::Legacy);
93622db1728SEd Tanous                 }
93722db1728SEd Tanous             }
93822db1728SEd Tanous             BMCWEB_LOG_DEBUG << "Parent item not found";
93996825bebSEd Tanous             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
94022db1728SEd Tanous             },
94122db1728SEd Tanous             service, "/xyz/openbmc_project/VirtualMedia",
942002d39b4SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9432b73119cSGeorge Liu         });
94496825bebSEd Tanous }
94596825bebSEd Tanous 
94696825bebSEd Tanous inline void handleManagersVirtualMediaCollectionGet(
94796825bebSEd Tanous     crow::App& app, const crow::Request& req,
94822db1728SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94996825bebSEd Tanous     const std::string& name)
95096825bebSEd Tanous {
9513ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95245ca1b86SEd Tanous     {
95345ca1b86SEd Tanous         return;
95445ca1b86SEd Tanous     }
95522db1728SEd Tanous     if (name != "bmc")
95622db1728SEd Tanous     {
957002d39b4SEd Tanous         messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
958107077deSPrzemyslaw Czarnowski 
959107077deSPrzemyslaw Czarnowski         return;
960107077deSPrzemyslaw Czarnowski     }
961107077deSPrzemyslaw Czarnowski 
9628d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
963107077deSPrzemyslaw Czarnowski         "#VirtualMediaCollection.VirtualMediaCollection";
9648d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
965fdb20347SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
966fdb20347SEd Tanous         "redfish", "v1", "Managers", name, "VirtualMedia");
967107077deSPrzemyslaw Czarnowski 
9682b73119cSGeorge Liu     dbus::utility::getDbusObject(
9692b73119cSGeorge Liu         "/xyz/openbmc_project/VirtualMedia", {},
9702b73119cSGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
971b9d36b47SEd Tanous                           const dbus::utility::MapperGetObject& getObjectType) {
972107077deSPrzemyslaw Czarnowski         if (ec)
973107077deSPrzemyslaw Czarnowski         {
97496825bebSEd Tanous             BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " << ec;
975107077deSPrzemyslaw Czarnowski             messages::internalError(asyncResp->res);
976107077deSPrzemyslaw Czarnowski 
977107077deSPrzemyslaw Czarnowski             return;
978107077deSPrzemyslaw Czarnowski         }
979107077deSPrzemyslaw Czarnowski         std::string service = getObjectType.begin()->first;
980107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
981107077deSPrzemyslaw Czarnowski 
982107077deSPrzemyslaw Czarnowski         getVmResourceList(asyncResp, service, name);
9832b73119cSGeorge Liu         });
98496825bebSEd Tanous }
985107077deSPrzemyslaw Czarnowski 
98696825bebSEd Tanous inline void
98796825bebSEd Tanous     handleVirtualMediaGet(crow::App& app, const crow::Request& req,
98822db1728SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
98996825bebSEd Tanous                           const std::string& name, const std::string& resName)
99096825bebSEd Tanous {
9913ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99245ca1b86SEd Tanous     {
99345ca1b86SEd Tanous         return;
99445ca1b86SEd Tanous     }
995107077deSPrzemyslaw Czarnowski     if (name != "bmc")
996107077deSPrzemyslaw Czarnowski     {
997002d39b4SEd Tanous         messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
998107077deSPrzemyslaw Czarnowski 
999107077deSPrzemyslaw Czarnowski         return;
1000107077deSPrzemyslaw Czarnowski     }
1001107077deSPrzemyslaw Czarnowski 
10022b73119cSGeorge Liu     dbus::utility::getDbusObject(
10032b73119cSGeorge Liu         "/xyz/openbmc_project/VirtualMedia", {},
1004002d39b4SEd Tanous         [asyncResp, name,
10052b73119cSGeorge Liu          resName](const boost::system::error_code& ec,
1006b9d36b47SEd Tanous                   const dbus::utility::MapperGetObject& getObjectType) {
1007107077deSPrzemyslaw Czarnowski         if (ec)
1008107077deSPrzemyslaw Czarnowski         {
100996825bebSEd Tanous             BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: " << ec;
1010107077deSPrzemyslaw Czarnowski             messages::internalError(asyncResp->res);
1011107077deSPrzemyslaw Czarnowski 
1012107077deSPrzemyslaw Czarnowski             return;
1013107077deSPrzemyslaw Czarnowski         }
1014107077deSPrzemyslaw Czarnowski         std::string service = getObjectType.begin()->first;
1015107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1016107077deSPrzemyslaw Czarnowski 
1017107077deSPrzemyslaw Czarnowski         getVmData(asyncResp, service, name, resName);
10182b73119cSGeorge Liu         });
101996825bebSEd Tanous }
102096825bebSEd Tanous 
102196825bebSEd Tanous inline void requestNBDVirtualMediaRoutes(App& app)
102296825bebSEd Tanous {
102396825bebSEd Tanous     BMCWEB_ROUTE(
102496825bebSEd Tanous         app,
102596825bebSEd Tanous         "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia")
102696825bebSEd Tanous         .privileges(redfish::privileges::postVirtualMedia)
102796825bebSEd Tanous         .methods(boost::beast::http::verb::post)(std::bind_front(
102896825bebSEd Tanous             handleManagersVirtualMediaActionInsertPost, std::ref(app)));
102996825bebSEd Tanous 
103096825bebSEd Tanous     BMCWEB_ROUTE(
103196825bebSEd Tanous         app,
103296825bebSEd Tanous         "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia")
103396825bebSEd Tanous         .privileges(redfish::privileges::postVirtualMedia)
103496825bebSEd Tanous         .methods(boost::beast::http::verb::post)(std::bind_front(
103596825bebSEd Tanous             handleManagersVirtualMediaActionEject, std::ref(app)));
103696825bebSEd Tanous 
103796825bebSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/")
103896825bebSEd Tanous         .privileges(redfish::privileges::getVirtualMediaCollection)
103996825bebSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
104096825bebSEd Tanous             handleManagersVirtualMediaCollectionGet, std::ref(app)));
104196825bebSEd Tanous 
104296825bebSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/")
104396825bebSEd Tanous         .privileges(redfish::privileges::getVirtualMedia)
104496825bebSEd Tanous         .methods(boost::beast::http::verb::get)(
104596825bebSEd Tanous             std::bind_front(handleVirtualMediaGet, std::ref(app)));
1046107077deSPrzemyslaw Czarnowski }
1047107077deSPrzemyslaw Czarnowski 
1048107077deSPrzemyslaw Czarnowski } // namespace redfish
1049