xref: /openbmc/bmcweb/features/redfish/lib/network_protocol.hpp (revision 253f11b84347de6bff7c6b624bef270fefae5f5a)
170141561SBorawski.Lukasz /*
270141561SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation
370141561SBorawski.Lukasz //
470141561SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License");
570141561SBorawski.Lukasz // you may not use this file except in compliance with the License.
670141561SBorawski.Lukasz // You may obtain a copy of the License at
770141561SBorawski.Lukasz //
870141561SBorawski.Lukasz //      http://www.apache.org/licenses/LICENSE-2.0
970141561SBorawski.Lukasz //
1070141561SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software
1170141561SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS,
1270141561SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1370141561SBorawski.Lukasz // See the License for the specific language governing permissions and
1470141561SBorawski.Lukasz // limitations under the License.
1570141561SBorawski.Lukasz */
1670141561SBorawski.Lukasz #pragma once
1770141561SBorawski.Lukasz 
183ccb3adbSEd Tanous #include "app.hpp"
193ccb3adbSEd Tanous #include "dbus_utility.hpp"
203a8a0088SKowalski, Kamil #include "error_messages.hpp"
2167a78d87STom Joseph #include "openbmc_dbus_rest.hpp"
223ccb3adbSEd Tanous #include "query.hpp"
23b4bec66bSAbhishek Patel #include "redfish_util.hpp"
243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
253ccb3adbSEd Tanous #include "utils/json_utils.hpp"
263ccb3adbSEd Tanous #include "utils/stl_utils.hpp"
2770141561SBorawski.Lukasz 
28e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
29*253f11b8SEd Tanous #include <boost/url/format.hpp>
301e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
311214b7e7SGunnar Mills 
32e99073f5SGeorge Liu #include <array>
331214b7e7SGunnar Mills #include <optional>
34e99073f5SGeorge Liu #include <string_view>
35abf2add6SEd Tanous #include <variant>
365f4c798dSJiaqing Zhao 
371abe55efSEd Tanous namespace redfish
381abe55efSEd Tanous {
3970141561SBorawski.Lukasz 
407e860f15SJohn Edward Broadbent void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
417e860f15SJohn Edward Broadbent std::string getHostName();
427e860f15SJohn Edward Broadbent 
435c3e9272SAbhishek Patel static constexpr std::string_view sshServiceName = "dropbear";
445c3e9272SAbhishek Patel static constexpr std::string_view httpsServiceName = "bmcweb";
455c3e9272SAbhishek Patel static constexpr std::string_view ipmiServiceName = "phosphor-ipmi-net";
465c3e9272SAbhishek Patel 
475c3e9272SAbhishek Patel // Mapping from Redfish NetworkProtocol key name to backend service that hosts
485c3e9272SAbhishek Patel // that protocol.
495c3e9272SAbhishek Patel static constexpr std::array<std::pair<std::string_view, std::string_view>, 3>
505c3e9272SAbhishek Patel     networkProtocolToDbus = {{{"SSH", sshServiceName},
5169320d54SJiaqing Zhao                               {"HTTPS", httpsServiceName},
5269320d54SJiaqing Zhao                               {"IPMI", ipmiServiceName}}};
533a8a0088SKowalski, Kamil 
54711ac7a9SEd Tanous inline void extractNTPServersAndDomainNamesData(
55711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType& dbusData,
56532d7697SGunnar Mills     std::vector<std::string>& ntpData, std::vector<std::string>& dnData)
5720e6ea5dSraviteja-b {
5881ce609eSEd Tanous     for (const auto& obj : dbusData)
5920e6ea5dSraviteja-b     {
6020e6ea5dSraviteja-b         for (const auto& ifacePair : obj.second)
6120e6ea5dSraviteja-b         {
620a052baaSGeorge Liu             if (ifacePair.first !=
6320e6ea5dSraviteja-b                 "xyz.openbmc_project.Network.EthernetInterface")
6420e6ea5dSraviteja-b             {
650a052baaSGeorge Liu                 continue;
660a052baaSGeorge Liu             }
670a052baaSGeorge Liu 
6820e6ea5dSraviteja-b             for (const auto& propertyPair : ifacePair.second)
6920e6ea5dSraviteja-b             {
70fcd2682aSEd Tanous                 if (propertyPair.first == "StaticNTPServers")
7120e6ea5dSraviteja-b                 {
7220e6ea5dSraviteja-b                     const std::vector<std::string>* ntpServers =
738d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
7420e6ea5dSraviteja-b                             &propertyPair.second);
7520e6ea5dSraviteja-b                     if (ntpServers != nullptr)
7620e6ea5dSraviteja-b                     {
77c251fe81SJian Zhang                         ntpData.insert(ntpData.end(), ntpServers->begin(),
78c251fe81SJian Zhang                                        ntpServers->end());
7920e6ea5dSraviteja-b                     }
8020e6ea5dSraviteja-b                 }
81d24bfc7aSJennifer Lee                 else if (propertyPair.first == "DomainName")
82d24bfc7aSJennifer Lee                 {
83d24bfc7aSJennifer Lee                     const std::vector<std::string>* domainNames =
848d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
85d24bfc7aSJennifer Lee                             &propertyPair.second);
86d24bfc7aSJennifer Lee                     if (domainNames != nullptr)
87d24bfc7aSJennifer Lee                     {
88c251fe81SJian Zhang                         dnData.insert(dnData.end(), domainNames->begin(),
89c251fe81SJian Zhang                                       domainNames->end());
90d24bfc7aSJennifer Lee                     }
91d24bfc7aSJennifer Lee                 }
9220e6ea5dSraviteja-b             }
9320e6ea5dSraviteja-b         }
9420e6ea5dSraviteja-b     }
950225b87bSEd Tanous     stl_utils::removeDuplicate(ntpData);
96c251fe81SJian Zhang     stl_utils::removeDuplicate(dnData);
9720e6ea5dSraviteja-b }
9820e6ea5dSraviteja-b 
9920e6ea5dSraviteja-b template <typename CallbackFunc>
10020e6ea5dSraviteja-b void getEthernetIfaceData(CallbackFunc&& callback)
10120e6ea5dSraviteja-b {
1025eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1035eb468daSGeorge Liu     dbus::utility::getManagedObjects(
1045eb468daSGeorge Liu         "xyz.openbmc_project.Network", path,
1058cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback)](
1068b24275dSEd Tanous             const boost::system::error_code& ec,
107711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& dbusData) {
10820e6ea5dSraviteja-b         std::vector<std::string> ntpServers;
109d24bfc7aSJennifer Lee         std::vector<std::string> domainNames;
11020e6ea5dSraviteja-b 
1118b24275dSEd Tanous         if (ec)
11220e6ea5dSraviteja-b         {
113532d7697SGunnar Mills             callback(false, ntpServers, domainNames);
11420e6ea5dSraviteja-b             return;
11520e6ea5dSraviteja-b         }
11620e6ea5dSraviteja-b 
117532d7697SGunnar Mills         extractNTPServersAndDomainNamesData(dbusData, ntpServers, domainNames);
11820e6ea5dSraviteja-b 
119532d7697SGunnar Mills         callback(true, ntpServers, domainNames);
1205eb468daSGeorge Liu     });
121271584abSEd Tanous }
12220e6ea5dSraviteja-b 
1235c3e9272SAbhishek Patel inline void afterNetworkPortRequest(
1245c3e9272SAbhishek Patel     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1255c3e9272SAbhishek Patel     const boost::system::error_code& ec,
1265c3e9272SAbhishek Patel     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
1275c3e9272SAbhishek Patel {
1285c3e9272SAbhishek Patel     if (ec)
1295c3e9272SAbhishek Patel     {
1305c3e9272SAbhishek Patel         messages::internalError(asyncResp->res);
1315c3e9272SAbhishek Patel         return;
1325c3e9272SAbhishek Patel     }
1335c3e9272SAbhishek Patel     for (const auto& data : socketData)
1345c3e9272SAbhishek Patel     {
1355c3e9272SAbhishek Patel         const std::string& socketPath = get<0>(data);
1365c3e9272SAbhishek Patel         const std::string& protocolName = get<1>(data);
1375c3e9272SAbhishek Patel         bool isProtocolEnabled = get<2>(data);
1385c3e9272SAbhishek Patel 
1395c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
1405c3e9272SAbhishek Patel             isProtocolEnabled;
1415c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["Port"] = nullptr;
1425c3e9272SAbhishek Patel         getPortNumber(socketPath, [asyncResp, protocolName](
1435c3e9272SAbhishek Patel                                       const boost::system::error_code& ec2,
1445c3e9272SAbhishek Patel                                       int portNumber) {
1455c3e9272SAbhishek Patel             if (ec2)
1465c3e9272SAbhishek Patel             {
1475c3e9272SAbhishek Patel                 messages::internalError(asyncResp->res);
1485c3e9272SAbhishek Patel                 return;
1495c3e9272SAbhishek Patel             }
1505c3e9272SAbhishek Patel             asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
1515c3e9272SAbhishek Patel         });
1525c3e9272SAbhishek Patel     }
1535c3e9272SAbhishek Patel }
1545c3e9272SAbhishek Patel 
1554f48d5f6SEd Tanous inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15672048780SAbhishek Patel                            const crow::Request& req)
1571abe55efSEd Tanous {
1583e72c202SNinad Palsule     if (req.session == nullptr)
1593e72c202SNinad Palsule     {
1603e72c202SNinad Palsule         messages::internalError(asyncResp->res);
1613e72c202SNinad Palsule         return;
1623e72c202SNinad Palsule     }
1633e72c202SNinad Palsule 
164e9f71672SEd Tanous     asyncResp->res.addHeader(
165e9f71672SEd Tanous         boost::beast::http::field::link,
166e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/NetworkProtocol.json>; rel=describedby");
1670f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
168532d7697SGunnar Mills         "#ManagerNetworkProtocol.v1_5_0.ManagerNetworkProtocol";
1690f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
170*253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
171*253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
1720f74e643SEd Tanous     asyncResp->res.jsonValue["Id"] = "NetworkProtocol";
1730f74e643SEd Tanous     asyncResp->res.jsonValue["Name"] = "Manager Network Protocol";
1740f74e643SEd Tanous     asyncResp->res.jsonValue["Description"] = "Manager Network Service";
1750f74e643SEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = "OK";
1760f74e643SEd Tanous     asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
1770f74e643SEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
1780f74e643SEd Tanous 
17961932318SXiaochao Ma     // HTTP is Mandatory attribute as per OCP Baseline Profile - v1.0.0,
180818ea7b8SJoshi-Mansi     // but from security perspective it is not recommended to use.
181818ea7b8SJoshi-Mansi     // Hence using protocolEnabled as false to make it OCP and security-wise
182818ea7b8SJoshi-Mansi     // compliant
1835c3e9272SAbhishek Patel     asyncResp->res.jsonValue["HTTP"]["Port"] = nullptr;
184818ea7b8SJoshi-Mansi     asyncResp->res.jsonValue["HTTP"]["ProtocolEnabled"] = false;
185818ea7b8SJoshi-Mansi 
1861ee2db7fSAndrew Geissler     // The ProtocolEnabled of the following protocols is determined by
1871ee2db7fSAndrew Geissler     // inspecting the state of associated systemd sockets. If these protocols
1881ee2db7fSAndrew Geissler     // have been disabled, then the systemd socket unit files will not be found
1891ee2db7fSAndrew Geissler     // and the protocols will not be returned in this Redfish query. Set some
1901ee2db7fSAndrew Geissler     // defaults to ensure something is always returned.
1911ee2db7fSAndrew Geissler     for (const auto& nwkProtocol : networkProtocolToDbus)
1921ee2db7fSAndrew Geissler     {
1931ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["Port"] = nullptr;
1941ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["ProtocolEnabled"] = false;
1951ee2db7fSAndrew Geissler     }
1961ee2db7fSAndrew Geissler 
197d24bfc7aSJennifer Lee     std::string hostName = getHostName();
198d24bfc7aSJennifer Lee 
199d24bfc7aSJennifer Lee     asyncResp->res.jsonValue["HostName"] = hostName;
2003a8a0088SKowalski, Kamil 
20120e6ea5dSraviteja-b     getNTPProtocolEnabled(asyncResp);
20220e6ea5dSraviteja-b 
203002d39b4SEd Tanous     getEthernetIfaceData(
204002d39b4SEd Tanous         [hostName, asyncResp](const bool& success,
20502cad96eSEd Tanous                               const std::vector<std::string>& ntpServers,
206d24bfc7aSJennifer Lee                               const std::vector<std::string>& domainNames) {
20720e6ea5dSraviteja-b         if (!success)
20820e6ea5dSraviteja-b         {
2090a052baaSGeorge Liu             messages::resourceNotFound(asyncResp->res, "ManagerNetworkProtocol",
2100a052baaSGeorge Liu                                        "NetworkProtocol");
21120e6ea5dSraviteja-b             return;
21220e6ea5dSraviteja-b         }
21320e6ea5dSraviteja-b         asyncResp->res.jsonValue["NTP"]["NTPServers"] = ntpServers;
21426f6976fSEd Tanous         if (!hostName.empty())
215d24bfc7aSJennifer Lee         {
216f23b7296SEd Tanous             std::string fqdn = hostName;
21726f6976fSEd Tanous             if (!domainNames.empty())
218d24bfc7aSJennifer Lee             {
219f23b7296SEd Tanous                 fqdn += ".";
220f23b7296SEd Tanous                 fqdn += domainNames[0];
221d24bfc7aSJennifer Lee             }
2222c70f800SEd Tanous             asyncResp->res.jsonValue["FQDN"] = std::move(fqdn);
223d24bfc7aSJennifer Lee         }
22420e6ea5dSraviteja-b     });
22520e6ea5dSraviteja-b 
22672048780SAbhishek Patel     Privileges effectiveUserPrivileges =
2273e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
22872048780SAbhishek Patel 
22972048780SAbhishek Patel     // /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
23072048780SAbhishek Patel     // something only ConfigureManager can access then only display when
23172048780SAbhishek Patel     // the user has permissions ConfigureManager
23272048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
23372048780SAbhishek Patel                                          effectiveUserPrivileges))
23472048780SAbhishek Patel     {
2351476687dSEd Tanous         asyncResp->res.jsonValue["HTTPS"]["Certificates"]["@odata.id"] =
236*253f11b8SEd Tanous             boost::urls::format(
237*253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
238*253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
23970141561SBorawski.Lukasz     }
24070141561SBorawski.Lukasz 
2415c3e9272SAbhishek Patel     getPortStatusAndPath(std::span(networkProtocolToDbus),
2425c3e9272SAbhishek Patel                          std::bind_front(afterNetworkPortRequest, asyncResp));
243b4bec66bSAbhishek Patel } // namespace redfish
244501be32bSraviteja-b 
2458e157735SEd Tanous inline void afterSetNTP(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2468e157735SEd Tanous                         const boost::system::error_code& ec)
24720e6ea5dSraviteja-b {
2488e157735SEd Tanous     if (ec)
24920e6ea5dSraviteja-b     {
2508e157735SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
2518e157735SEd Tanous                          ec);
2528e157735SEd Tanous         messages::internalError(asyncResp->res);
2538e157735SEd Tanous         return;
25420e6ea5dSraviteja-b     }
2558e157735SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
25620e6ea5dSraviteja-b }
25720e6ea5dSraviteja-b 
2588e157735SEd Tanous inline void handleNTPProtocolEnabled(
2598e157735SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool ntpEnabled)
2608e157735SEd Tanous {
2618e157735SEd Tanous     bool interactive = false;
2628e157735SEd Tanous     auto callback = [asyncResp](const boost::system::error_code& ec) {
2638e157735SEd Tanous         afterSetNTP(asyncResp, ec);
2648e157735SEd Tanous     };
2658e157735SEd Tanous     crow::connections::systemBus->async_method_call(
2668e157735SEd Tanous         std::move(callback), "org.freedesktop.timedate1",
2678e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP",
2688e157735SEd Tanous         ntpEnabled, interactive);
26920e6ea5dSraviteja-b }
27020e6ea5dSraviteja-b 
271ed4de7a8SEd Tanous // Redfish states that ip addresses can be
272ed4de7a8SEd Tanous // string, to set a value
273ed4de7a8SEd Tanous // null, to delete the value
274ed4de7a8SEd Tanous // object_t, empty json object, to ignore the value
275ed4de7a8SEd Tanous using IpAddress =
276ed4de7a8SEd Tanous     std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>;
277ed4de7a8SEd Tanous 
2784f48d5f6SEd Tanous inline void
279287ece64SGeorge Liu     handleNTPServersPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
280ed4de7a8SEd Tanous                           const std::vector<IpAddress>& ntpServerObjects,
281b9e15228SEd Tanous                           std::vector<std::string> currentNtpServers)
28220e6ea5dSraviteja-b {
283b9e15228SEd Tanous     std::vector<std::string>::iterator currentNtpServer =
284b9e15228SEd Tanous         currentNtpServers.begin();
285b9e15228SEd Tanous     for (size_t index = 0; index < ntpServerObjects.size(); index++)
286287ece64SGeorge Liu     {
287ed4de7a8SEd Tanous         const IpAddress& ntpServer = ntpServerObjects[index];
288ed4de7a8SEd Tanous         if (std::holds_alternative<std::nullptr_t>(ntpServer))
289b9e15228SEd Tanous         {
290b9e15228SEd Tanous             // Can't delete an item that doesn't exist
291b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
292b9e15228SEd Tanous             {
293b9e15228SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, "null",
294b9e15228SEd Tanous                                                  "NTP/NTPServers/" +
295b9e15228SEd Tanous                                                      std::to_string(index));
296b9e15228SEd Tanous 
297287ece64SGeorge Liu                 return;
298287ece64SGeorge Liu             }
299b9e15228SEd Tanous             currentNtpServer = currentNtpServers.erase(currentNtpServer);
300b9e15228SEd Tanous             continue;
301b9e15228SEd Tanous         }
302b9e15228SEd Tanous         const nlohmann::json::object_t* ntpServerObject =
303ed4de7a8SEd Tanous             std::get_if<nlohmann::json::object_t>(&ntpServer);
304b9e15228SEd Tanous         if (ntpServerObject != nullptr)
305b9e15228SEd Tanous         {
306b9e15228SEd Tanous             if (!ntpServerObject->empty())
307b9e15228SEd Tanous             {
308ed4de7a8SEd Tanous                 messages::propertyValueNotInList(
309ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
310ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
311b9e15228SEd Tanous                 return;
312b9e15228SEd Tanous             }
313b9e15228SEd Tanous             // Can't retain an item that doesn't exist
314b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
315b9e15228SEd Tanous             {
316ed4de7a8SEd Tanous                 messages::propertyValueOutOfRange(
317ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
318ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
319b9e15228SEd Tanous 
320b9e15228SEd Tanous                 return;
321b9e15228SEd Tanous             }
322b9e15228SEd Tanous             // empty objects should leave the NtpServer unmodified
323b9e15228SEd Tanous             currentNtpServer++;
324b9e15228SEd Tanous             continue;
325b9e15228SEd Tanous         }
326b9e15228SEd Tanous 
327ed4de7a8SEd Tanous         const std::string* ntpServerStr = std::get_if<std::string>(&ntpServer);
328b9e15228SEd Tanous         if (ntpServerStr == nullptr)
329b9e15228SEd Tanous         {
330ed4de7a8SEd Tanous             messages::internalError(asyncResp->res);
331b9e15228SEd Tanous             return;
332b9e15228SEd Tanous         }
333b9e15228SEd Tanous         if (currentNtpServer == currentNtpServers.end())
334b9e15228SEd Tanous         {
335b9e15228SEd Tanous             // if we're at the end of the list, append to the end
336b9e15228SEd Tanous             currentNtpServers.push_back(*ntpServerStr);
337b9e15228SEd Tanous             currentNtpServer = currentNtpServers.end();
338b9e15228SEd Tanous             continue;
339b9e15228SEd Tanous         }
340b9e15228SEd Tanous         *currentNtpServer = *ntpServerStr;
341b9e15228SEd Tanous         currentNtpServer++;
342b9e15228SEd Tanous     }
343b9e15228SEd Tanous 
344b9e15228SEd Tanous     // Any remaining array elements should be removed
345b9e15228SEd Tanous     currentNtpServers.erase(currentNtpServer, currentNtpServers.end());
346287ece64SGeorge Liu 
347e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> ethInterfaces = {
348e99073f5SGeorge Liu         "xyz.openbmc_project.Network.EthernetInterface"};
349e99073f5SGeorge Liu     dbus::utility::getSubTree(
350e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, ethInterfaces,
351b9e15228SEd Tanous         [asyncResp, currentNtpServers](
3522138483cSGeorge Liu             const boost::system::error_code& ec,
353b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
3540a052baaSGeorge Liu         if (ec)
3550a052baaSGeorge Liu         {
35662598e31SEd Tanous             BMCWEB_LOG_WARNING("D-Bus error: {}, {}", ec, ec.message());
3570a052baaSGeorge Liu             messages::internalError(asyncResp->res);
3580a052baaSGeorge Liu             return;
3590a052baaSGeorge Liu         }
3600a052baaSGeorge Liu 
3610a052baaSGeorge Liu         for (const auto& [objectPath, serviceMap] : subtree)
3620a052baaSGeorge Liu         {
3630a052baaSGeorge Liu             for (const auto& [service, interfaces] : serviceMap)
3640a052baaSGeorge Liu             {
3650a052baaSGeorge Liu                 for (const auto& interface : interfaces)
3660a052baaSGeorge Liu                 {
3670a052baaSGeorge Liu                     if (interface !=
3680a052baaSGeorge Liu                         "xyz.openbmc_project.Network.EthernetInterface")
3690a052baaSGeorge Liu                     {
3700a052baaSGeorge Liu                         continue;
3710a052baaSGeorge Liu                     }
3720a052baaSGeorge Liu 
37387c44966SAsmitha Karunanithi                     setDbusProperty(asyncResp, service, objectPath, interface,
37487c44966SAsmitha Karunanithi                                     "StaticNTPServers", "NTP/NTPServers/",
37587c44966SAsmitha Karunanithi                                     currentNtpServers);
37620e6ea5dSraviteja-b                 }
3770a052baaSGeorge Liu             }
3780a052baaSGeorge Liu         }
379e99073f5SGeorge Liu     });
3800a052baaSGeorge Liu }
38120e6ea5dSraviteja-b 
3824f48d5f6SEd Tanous inline void
3834f48d5f6SEd Tanous     handleProtocolEnabled(const bool protocolEnabled,
384e5a99777SAlbert Zhang                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
38569320d54SJiaqing Zhao                           const std::string& netBasePath)
38667a78d87STom Joseph {
387e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
388e99073f5SGeorge Liu         "xyz.openbmc_project.Control.Service.Attributes"};
389e99073f5SGeorge Liu     dbus::utility::getSubTree(
390e99073f5SGeorge Liu         "/xyz/openbmc_project/control/service", 0, interfaces,
391e5a99777SAlbert Zhang         [protocolEnabled, asyncResp,
3922138483cSGeorge Liu          netBasePath](const boost::system::error_code& ec,
393b9d36b47SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
39467a78d87STom Joseph         if (ec)
39567a78d87STom Joseph         {
39667a78d87STom Joseph             messages::internalError(asyncResp->res);
39767a78d87STom Joseph             return;
39867a78d87STom Joseph         }
39967a78d87STom Joseph 
40067a78d87STom Joseph         for (const auto& entry : subtree)
40167a78d87STom Joseph         {
40218f8f608SEd Tanous             if (entry.first.starts_with(netBasePath))
40367a78d87STom Joseph             {
40487c44966SAsmitha Karunanithi                 setDbusProperty(
40587c44966SAsmitha Karunanithi                     asyncResp, entry.second.begin()->first, entry.first,
406002d39b4SEd Tanous                     "xyz.openbmc_project.Control.Service.Attributes", "Running",
40787c44966SAsmitha Karunanithi                     "IPMI/ProtocolEnabled", protocolEnabled);
40887c44966SAsmitha Karunanithi                 setDbusProperty(
40987c44966SAsmitha Karunanithi                     asyncResp, entry.second.begin()->first, entry.first,
410002d39b4SEd Tanous                     "xyz.openbmc_project.Control.Service.Attributes", "Enabled",
41187c44966SAsmitha Karunanithi                     "IPMI/ProtocolEnabled", protocolEnabled);
41267a78d87STom Joseph             }
41367a78d87STom Joseph         }
414e99073f5SGeorge Liu     });
41567a78d87STom Joseph }
41667a78d87STom Joseph 
4174f48d5f6SEd Tanous inline std::string getHostName()
418501be32bSraviteja-b {
4197e860f15SJohn Edward Broadbent     std::string hostName;
4208d1b46d7Szhanghch05 
421d3a9e084SEd Tanous     std::array<char, HOST_NAME_MAX> hostNameCStr{};
4227e860f15SJohn Edward Broadbent     if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0)
4237e860f15SJohn Edward Broadbent     {
4247e860f15SJohn Edward Broadbent         hostName = hostNameCStr.data();
4257e860f15SJohn Edward Broadbent     }
4267e860f15SJohn Edward Broadbent     return hostName;
4277e860f15SJohn Edward Broadbent }
4287e860f15SJohn Edward Broadbent 
4294f48d5f6SEd Tanous inline void
4304f48d5f6SEd Tanous     getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4317e860f15SJohn Edward Broadbent {
4328e157735SEd Tanous     sdbusplus::asio::getProperty<bool>(
4338e157735SEd Tanous         *crow::connections::systemBus, "org.freedesktop.timedate1",
4348e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP",
4358e157735SEd Tanous         [asyncResp](const boost::system::error_code& ec, bool enabled) {
4368b24275dSEd Tanous         if (ec)
4377e860f15SJohn Edward Broadbent         {
4388e157735SEd Tanous             BMCWEB_LOG_WARNING(
4398e157735SEd Tanous                 "Failed to get NTP status, assuming not supported");
4407e860f15SJohn Edward Broadbent             return;
4417e860f15SJohn Edward Broadbent         }
4427e860f15SJohn Edward Broadbent 
4438e157735SEd Tanous         asyncResp->res.jsonValue["NTP"]["ProtocolEnabled"] = enabled;
4441e1e598dSJonathan Doman     });
4457e860f15SJohn Edward Broadbent }
4467e860f15SJohn Edward Broadbent 
4475c3e9272SAbhishek Patel inline std::string encodeServiceObjectPath(std::string_view serviceName)
44869320d54SJiaqing Zhao {
44969320d54SJiaqing Zhao     sdbusplus::message::object_path objPath(
45069320d54SJiaqing Zhao         "/xyz/openbmc_project/control/service");
45169320d54SJiaqing Zhao     objPath /= serviceName;
45269320d54SJiaqing Zhao     return objPath.str;
45369320d54SJiaqing Zhao }
45469320d54SJiaqing Zhao 
4550f55d946SEd Tanous inline void handleBmcNetworkProtocolHead(
456e9f71672SEd Tanous     crow::App& app, const crow::Request& req,
457e9f71672SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
458e9f71672SEd Tanous {
459e9f71672SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
460e9f71672SEd Tanous     {
461e9f71672SEd Tanous         return;
462e9f71672SEd Tanous     }
463e9f71672SEd Tanous     asyncResp->res.addHeader(
464e9f71672SEd Tanous         boost::beast::http::field::link,
465e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
466e9f71672SEd Tanous }
467e9f71672SEd Tanous 
468e634b34cSEd Tanous inline void handleManagersNetworkProtocolPatch(
469e634b34cSEd Tanous     App& app, const crow::Request& req,
470*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
471*253f11b8SEd Tanous     const std::string& managerId)
4727e860f15SJohn Edward Broadbent {
4733ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
47445ca1b86SEd Tanous     {
47545ca1b86SEd Tanous         return;
47645ca1b86SEd Tanous     }
477*253f11b8SEd Tanous 
478*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
479*253f11b8SEd Tanous     {
480*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
481*253f11b8SEd Tanous         return;
482*253f11b8SEd Tanous     }
483*253f11b8SEd Tanous 
484501be32bSraviteja-b     std::optional<std::string> newHostName;
485ed4de7a8SEd Tanous 
486ed4de7a8SEd Tanous     std::optional<std::vector<IpAddress>> ntpServerObjects;
4875f4c798dSJiaqing Zhao     std::optional<bool> ntpEnabled;
4885f4c798dSJiaqing Zhao     std::optional<bool> ipmiEnabled;
4895f4c798dSJiaqing Zhao     std::optional<bool> sshEnabled;
490501be32bSraviteja-b 
4915f4c798dSJiaqing Zhao     // clang-format off
4925f4c798dSJiaqing Zhao         if (!json_util::readJsonPatch(
4935f4c798dSJiaqing Zhao                 req, asyncResp->res,
4945f4c798dSJiaqing Zhao                 "HostName", newHostName,
495b9e15228SEd Tanous                 "NTP/NTPServers", ntpServerObjects,
4965f4c798dSJiaqing Zhao                 "NTP/ProtocolEnabled", ntpEnabled,
4975f4c798dSJiaqing Zhao                 "IPMI/ProtocolEnabled", ipmiEnabled,
4985f4c798dSJiaqing Zhao                 "SSH/ProtocolEnabled", sshEnabled))
499501be32bSraviteja-b         {
500501be32bSraviteja-b             return;
501501be32bSraviteja-b         }
5025f4c798dSJiaqing Zhao     // clang-format on
503cf05f9dcSJohnathan Mantey 
5048d1b46d7Szhanghch05     asyncResp->res.result(boost::beast::http::status::no_content);
505501be32bSraviteja-b     if (newHostName)
506501be32bSraviteja-b     {
5072db77d34SJohnathan Mantey         messages::propertyNotWritable(asyncResp->res, "HostName");
50844fad2aaSEd Tanous         return;
509cf05f9dcSJohnathan Mantey     }
510cf05f9dcSJohnathan Mantey 
51120e6ea5dSraviteja-b     if (ntpEnabled)
51220e6ea5dSraviteja-b     {
5138e157735SEd Tanous         handleNTPProtocolEnabled(asyncResp, *ntpEnabled);
51420e6ea5dSraviteja-b     }
515b9e15228SEd Tanous     if (ntpServerObjects)
51620e6ea5dSraviteja-b     {
517b9e15228SEd Tanous         getEthernetIfaceData(
518b9e15228SEd Tanous             [asyncResp, ntpServerObjects](
519e634b34cSEd Tanous                 const bool success, std::vector<std::string>& currentNtpServers,
520b9e15228SEd Tanous                 const std::vector<std::string>& /*domainNames*/) {
521b9e15228SEd Tanous             if (!success)
522b9e15228SEd Tanous             {
523b9e15228SEd Tanous                 messages::internalError(asyncResp->res);
524b9e15228SEd Tanous                 return;
525b9e15228SEd Tanous             }
526b9e15228SEd Tanous             handleNTPServersPatch(asyncResp, *ntpServerObjects,
527b9e15228SEd Tanous                                   std::move(currentNtpServers));
528b9e15228SEd Tanous         });
52920e6ea5dSraviteja-b     }
53067a78d87STom Joseph 
5315f4c798dSJiaqing Zhao     if (ipmiEnabled)
53267a78d87STom Joseph     {
533e5a99777SAlbert Zhang         handleProtocolEnabled(
5345f4c798dSJiaqing Zhao             *ipmiEnabled, asyncResp,
53569320d54SJiaqing Zhao             encodeServiceObjectPath(std::string(ipmiServiceName) + '@'));
536e5a99777SAlbert Zhang     }
537e5a99777SAlbert Zhang 
5385f4c798dSJiaqing Zhao     if (sshEnabled)
539e5a99777SAlbert Zhang     {
54069320d54SJiaqing Zhao         handleProtocolEnabled(*sshEnabled, asyncResp,
54169320d54SJiaqing Zhao                               encodeServiceObjectPath(sshServiceName));
54267a78d87STom Joseph     }
543e634b34cSEd Tanous }
544e634b34cSEd Tanous 
545af20dd1cSEd Tanous inline void handleManagersNetworkProtocolHead(
546e634b34cSEd Tanous     App& app, const crow::Request& req,
547*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
548*253f11b8SEd Tanous     const std::string& managerId)
549e634b34cSEd Tanous {
550e634b34cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
551e634b34cSEd Tanous     {
552e634b34cSEd Tanous         return;
553e634b34cSEd Tanous     }
554af20dd1cSEd Tanous     asyncResp->res.addHeader(
555af20dd1cSEd Tanous         boost::beast::http::field::link,
556af20dd1cSEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
557*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
558*253f11b8SEd Tanous     {
559*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
560*253f11b8SEd Tanous         return;
561*253f11b8SEd Tanous     }
562af20dd1cSEd Tanous }
563af20dd1cSEd Tanous 
564af20dd1cSEd Tanous inline void handleManagersNetworkProtocolGet(
565af20dd1cSEd Tanous     App& app, const crow::Request& req,
566*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567*253f11b8SEd Tanous     const std::string& managerId)
568af20dd1cSEd Tanous {
569*253f11b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
570*253f11b8SEd Tanous     {
571*253f11b8SEd Tanous         return;
572*253f11b8SEd Tanous     }
573*253f11b8SEd Tanous     asyncResp->res.addHeader(
574*253f11b8SEd Tanous         boost::beast::http::field::link,
575*253f11b8SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
576*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
577*253f11b8SEd Tanous     {
578*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
579*253f11b8SEd Tanous         return;
580*253f11b8SEd Tanous     }
581*253f11b8SEd Tanous 
582e634b34cSEd Tanous     getNetworkData(asyncResp, req);
583e634b34cSEd Tanous }
584e634b34cSEd Tanous 
585e634b34cSEd Tanous inline void requestRoutesNetworkProtocol(App& app)
586e634b34cSEd Tanous {
587*253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
588e634b34cSEd Tanous         .privileges(redfish::privileges::patchManagerNetworkProtocol)
589e634b34cSEd Tanous         .methods(boost::beast::http::verb::patch)(
590e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolPatch, std::ref(app)));
5917e860f15SJohn Edward Broadbent 
592*253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
593e9f71672SEd Tanous         .privileges(redfish::privileges::headManagerNetworkProtocol)
594e9f71672SEd Tanous         .methods(boost::beast::http::verb::head)(
595af20dd1cSEd Tanous             std::bind_front(handleManagersNetworkProtocolHead, std::ref(app)));
596e9f71672SEd Tanous 
597*253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
598ed398213SEd Tanous         .privileges(redfish::privileges::getManagerNetworkProtocol)
5997e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
600e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolGet, std::ref(app)));
601cf05f9dcSJohnathan Mantey }
60270141561SBorawski.Lukasz 
60370141561SBorawski.Lukasz } // namespace redfish
604