xref: /openbmc/bmcweb/features/redfish/lib/network_protocol.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
470141561SBorawski.Lukasz #pragma once
570141561SBorawski.Lukasz 
63ccb3adbSEd Tanous #include "app.hpp"
73ccb3adbSEd Tanous #include "dbus_utility.hpp"
83a8a0088SKowalski, Kamil #include "error_messages.hpp"
9539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
103ccb3adbSEd Tanous #include "query.hpp"
11b4bec66bSAbhishek Patel #include "redfish_util.hpp"
123ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
133ccb3adbSEd Tanous #include "utils/json_utils.hpp"
143ccb3adbSEd Tanous #include "utils/stl_utils.hpp"
1570141561SBorawski.Lukasz 
16e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
17253f11b8SEd Tanous #include <boost/url/format.hpp>
181e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
191214b7e7SGunnar Mills 
20e99073f5SGeorge Liu #include <array>
211214b7e7SGunnar Mills #include <optional>
22e99073f5SGeorge Liu #include <string_view>
23abf2add6SEd Tanous #include <variant>
240eebcefbSJishnu CM #include <vector>
255f4c798dSJiaqing Zhao 
261abe55efSEd Tanous namespace redfish
271abe55efSEd Tanous {
2870141561SBorawski.Lukasz 
297e860f15SJohn Edward Broadbent void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
307e860f15SJohn Edward Broadbent std::string getHostName();
317e860f15SJohn Edward Broadbent 
325c3e9272SAbhishek Patel static constexpr std::string_view sshServiceName = "dropbear";
335c3e9272SAbhishek Patel static constexpr std::string_view httpsServiceName = "bmcweb";
345c3e9272SAbhishek Patel static constexpr std::string_view ipmiServiceName = "phosphor-ipmi-net";
355c3e9272SAbhishek Patel 
365c3e9272SAbhishek Patel // Mapping from Redfish NetworkProtocol key name to backend service that hosts
375c3e9272SAbhishek Patel // that protocol.
385c3e9272SAbhishek Patel static constexpr std::array<std::pair<std::string_view, std::string_view>, 3>
395c3e9272SAbhishek Patel     networkProtocolToDbus = {{{"SSH", sshServiceName},
4069320d54SJiaqing Zhao                               {"HTTPS", httpsServiceName},
4169320d54SJiaqing Zhao                               {"IPMI", ipmiServiceName}}};
423a8a0088SKowalski, Kamil 
43711ac7a9SEd Tanous inline void extractNTPServersAndDomainNamesData(
44711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType& dbusData,
450eebcefbSJishnu CM     std::vector<std::string>& ntpData, std::vector<std::string>& dynamicNtpData,
460eebcefbSJishnu CM     std::vector<std::string>& dnData)
4720e6ea5dSraviteja-b {
4881ce609eSEd Tanous     for (const auto& obj : dbusData)
4920e6ea5dSraviteja-b     {
5020e6ea5dSraviteja-b         for (const auto& ifacePair : obj.second)
5120e6ea5dSraviteja-b         {
520a052baaSGeorge Liu             if (ifacePair.first !=
5320e6ea5dSraviteja-b                 "xyz.openbmc_project.Network.EthernetInterface")
5420e6ea5dSraviteja-b             {
550a052baaSGeorge Liu                 continue;
560a052baaSGeorge Liu             }
570a052baaSGeorge Liu 
5820e6ea5dSraviteja-b             for (const auto& propertyPair : ifacePair.second)
5920e6ea5dSraviteja-b             {
60fcd2682aSEd Tanous                 if (propertyPair.first == "StaticNTPServers")
6120e6ea5dSraviteja-b                 {
6220e6ea5dSraviteja-b                     const std::vector<std::string>* ntpServers =
638d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
6420e6ea5dSraviteja-b                             &propertyPair.second);
6520e6ea5dSraviteja-b                     if (ntpServers != nullptr)
6620e6ea5dSraviteja-b                     {
67c251fe81SJian Zhang                         ntpData.insert(ntpData.end(), ntpServers->begin(),
68c251fe81SJian Zhang                                        ntpServers->end());
6920e6ea5dSraviteja-b                     }
7020e6ea5dSraviteja-b                 }
710eebcefbSJishnu CM                 else if (propertyPair.first == "NTPServers")
720eebcefbSJishnu CM                 {
730eebcefbSJishnu CM                     const std::vector<std::string>* dynamicNtpServers =
740eebcefbSJishnu CM                         std::get_if<std::vector<std::string>>(
750eebcefbSJishnu CM                             &propertyPair.second);
760eebcefbSJishnu CM                     if (dynamicNtpServers != nullptr)
770eebcefbSJishnu CM                     {
780eebcefbSJishnu CM                         dynamicNtpData = *dynamicNtpServers;
790eebcefbSJishnu CM                     }
800eebcefbSJishnu CM                 }
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;
1090eebcefbSJishnu CM             std::vector<std::string> dynamicNtpServers;
110d24bfc7aSJennifer Lee             std::vector<std::string> domainNames;
11120e6ea5dSraviteja-b 
1128b24275dSEd Tanous             if (ec)
11320e6ea5dSraviteja-b             {
1140eebcefbSJishnu CM                 callback(false, ntpServers, dynamicNtpServers, domainNames);
11520e6ea5dSraviteja-b                 return;
11620e6ea5dSraviteja-b             }
11720e6ea5dSraviteja-b 
118bd79bce8SPatrick Williams             extractNTPServersAndDomainNamesData(dbusData, ntpServers,
1190eebcefbSJishnu CM                                                 dynamicNtpServers, domainNames);
12020e6ea5dSraviteja-b 
1210eebcefbSJishnu CM             callback(true, ntpServers, dynamicNtpServers, domainNames);
1225eb468daSGeorge Liu         });
123271584abSEd Tanous }
12420e6ea5dSraviteja-b 
1255c3e9272SAbhishek Patel inline void afterNetworkPortRequest(
1265c3e9272SAbhishek Patel     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1275c3e9272SAbhishek Patel     const boost::system::error_code& ec,
1285c3e9272SAbhishek Patel     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
1295c3e9272SAbhishek Patel {
1305c3e9272SAbhishek Patel     if (ec)
1315c3e9272SAbhishek Patel     {
1325c3e9272SAbhishek Patel         messages::internalError(asyncResp->res);
1335c3e9272SAbhishek Patel         return;
1345c3e9272SAbhishek Patel     }
1355c3e9272SAbhishek Patel     for (const auto& data : socketData)
1365c3e9272SAbhishek Patel     {
1375c3e9272SAbhishek Patel         const std::string& socketPath = get<0>(data);
1385c3e9272SAbhishek Patel         const std::string& protocolName = get<1>(data);
1395c3e9272SAbhishek Patel         bool isProtocolEnabled = get<2>(data);
1405c3e9272SAbhishek Patel 
1415c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
1425c3e9272SAbhishek Patel             isProtocolEnabled;
1435c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["Port"] = nullptr;
1445c3e9272SAbhishek Patel         getPortNumber(socketPath, [asyncResp, protocolName](
1455c3e9272SAbhishek Patel                                       const boost::system::error_code& ec2,
1465c3e9272SAbhishek Patel                                       int portNumber) {
1475c3e9272SAbhishek Patel             if (ec2)
1485c3e9272SAbhishek Patel             {
1495c3e9272SAbhishek Patel                 messages::internalError(asyncResp->res);
1505c3e9272SAbhishek Patel                 return;
1515c3e9272SAbhishek Patel             }
1525c3e9272SAbhishek Patel             asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
1535c3e9272SAbhishek Patel         });
1545c3e9272SAbhishek Patel     }
1555c3e9272SAbhishek Patel }
1565c3e9272SAbhishek Patel 
1574f48d5f6SEd Tanous inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15872048780SAbhishek Patel                            const crow::Request& req)
1591abe55efSEd Tanous {
1603e72c202SNinad Palsule     if (req.session == nullptr)
1613e72c202SNinad Palsule     {
1623e72c202SNinad Palsule         messages::internalError(asyncResp->res);
1633e72c202SNinad Palsule         return;
1643e72c202SNinad Palsule     }
1653e72c202SNinad Palsule 
166e9f71672SEd Tanous     asyncResp->res.addHeader(
167e9f71672SEd Tanous         boost::beast::http::field::link,
168e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/NetworkProtocol.json>; rel=describedby");
1690f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
1700eebcefbSJishnu CM         "#ManagerNetworkProtocol.v1_9_0.ManagerNetworkProtocol";
1710f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
172253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
173253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
1740f74e643SEd Tanous     asyncResp->res.jsonValue["Id"] = "NetworkProtocol";
1750f74e643SEd Tanous     asyncResp->res.jsonValue["Name"] = "Manager Network Protocol";
1760f74e643SEd Tanous     asyncResp->res.jsonValue["Description"] = "Manager Network Service";
177539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
178539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["HealthRollup"] = resource::Health::OK;
179539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
1800f74e643SEd Tanous 
18161932318SXiaochao Ma     // HTTP is Mandatory attribute as per OCP Baseline Profile - v1.0.0,
182818ea7b8SJoshi-Mansi     // but from security perspective it is not recommended to use.
183818ea7b8SJoshi-Mansi     // Hence using protocolEnabled as false to make it OCP and security-wise
184818ea7b8SJoshi-Mansi     // compliant
1855c3e9272SAbhishek Patel     asyncResp->res.jsonValue["HTTP"]["Port"] = nullptr;
186818ea7b8SJoshi-Mansi     asyncResp->res.jsonValue["HTTP"]["ProtocolEnabled"] = false;
187818ea7b8SJoshi-Mansi 
1881ee2db7fSAndrew Geissler     // The ProtocolEnabled of the following protocols is determined by
1891ee2db7fSAndrew Geissler     // inspecting the state of associated systemd sockets. If these protocols
1901ee2db7fSAndrew Geissler     // have been disabled, then the systemd socket unit files will not be found
1911ee2db7fSAndrew Geissler     // and the protocols will not be returned in this Redfish query. Set some
1921ee2db7fSAndrew Geissler     // defaults to ensure something is always returned.
1931ee2db7fSAndrew Geissler     for (const auto& nwkProtocol : networkProtocolToDbus)
1941ee2db7fSAndrew Geissler     {
1951ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["Port"] = nullptr;
1961ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["ProtocolEnabled"] = false;
1971ee2db7fSAndrew Geissler     }
1981ee2db7fSAndrew Geissler 
199d24bfc7aSJennifer Lee     std::string hostName = getHostName();
200d24bfc7aSJennifer Lee 
201d24bfc7aSJennifer Lee     asyncResp->res.jsonValue["HostName"] = hostName;
2023a8a0088SKowalski, Kamil 
20320e6ea5dSraviteja-b     getNTPProtocolEnabled(asyncResp);
20420e6ea5dSraviteja-b 
205bd79bce8SPatrick Williams     getEthernetIfaceData([hostName, asyncResp](
206bd79bce8SPatrick Williams                              const bool& success,
20702cad96eSEd Tanous                              const std::vector<std::string>& ntpServers,
2080eebcefbSJishnu CM                              const std::vector<std::string>& dynamicNtpServers,
209d24bfc7aSJennifer Lee                              const std::vector<std::string>& domainNames) {
21020e6ea5dSraviteja-b         if (!success)
21120e6ea5dSraviteja-b         {
2120a052baaSGeorge Liu             messages::resourceNotFound(asyncResp->res, "ManagerNetworkProtocol",
2130a052baaSGeorge Liu                                        "NetworkProtocol");
21420e6ea5dSraviteja-b             return;
21520e6ea5dSraviteja-b         }
21620e6ea5dSraviteja-b         asyncResp->res.jsonValue["NTP"]["NTPServers"] = ntpServers;
2170eebcefbSJishnu CM         asyncResp->res.jsonValue["NTP"]["NetworkSuppliedServers"] =
2180eebcefbSJishnu CM             dynamicNtpServers;
21926f6976fSEd Tanous         if (!hostName.empty())
220d24bfc7aSJennifer Lee         {
221f23b7296SEd Tanous             std::string fqdn = hostName;
22226f6976fSEd Tanous             if (!domainNames.empty())
223d24bfc7aSJennifer Lee             {
224f23b7296SEd Tanous                 fqdn += ".";
225f23b7296SEd Tanous                 fqdn += domainNames[0];
226d24bfc7aSJennifer Lee             }
2272c70f800SEd Tanous             asyncResp->res.jsonValue["FQDN"] = std::move(fqdn);
228d24bfc7aSJennifer Lee         }
22920e6ea5dSraviteja-b     });
23020e6ea5dSraviteja-b 
23172048780SAbhishek Patel     Privileges effectiveUserPrivileges =
2323e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
23372048780SAbhishek Patel 
23472048780SAbhishek Patel     // /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
23572048780SAbhishek Patel     // something only ConfigureManager can access then only display when
23672048780SAbhishek Patel     // the user has permissions ConfigureManager
23772048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
23872048780SAbhishek Patel                                          effectiveUserPrivileges))
23972048780SAbhishek Patel     {
2401476687dSEd Tanous         asyncResp->res.jsonValue["HTTPS"]["Certificates"]["@odata.id"] =
241253f11b8SEd Tanous             boost::urls::format(
242253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
243253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
24470141561SBorawski.Lukasz     }
24570141561SBorawski.Lukasz 
2465c3e9272SAbhishek Patel     getPortStatusAndPath(std::span(networkProtocolToDbus),
2475c3e9272SAbhishek Patel                          std::bind_front(afterNetworkPortRequest, asyncResp));
248b4bec66bSAbhishek Patel } // namespace redfish
249501be32bSraviteja-b 
2508e157735SEd Tanous inline void afterSetNTP(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2518e157735SEd Tanous                         const boost::system::error_code& ec)
25220e6ea5dSraviteja-b {
2538e157735SEd Tanous     if (ec)
25420e6ea5dSraviteja-b     {
2558e157735SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
2568e157735SEd Tanous                          ec);
2578e157735SEd Tanous         messages::internalError(asyncResp->res);
2588e157735SEd Tanous         return;
25920e6ea5dSraviteja-b     }
2608e157735SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
26120e6ea5dSraviteja-b }
26220e6ea5dSraviteja-b 
2638e157735SEd Tanous inline void handleNTPProtocolEnabled(
2648e157735SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool ntpEnabled)
2658e157735SEd Tanous {
2668e157735SEd Tanous     bool interactive = false;
2678e157735SEd Tanous     auto callback = [asyncResp](const boost::system::error_code& ec) {
2688e157735SEd Tanous         afterSetNTP(asyncResp, ec);
2698e157735SEd Tanous     };
2708e157735SEd Tanous     crow::connections::systemBus->async_method_call(
2718e157735SEd Tanous         std::move(callback), "org.freedesktop.timedate1",
2728e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP",
2738e157735SEd Tanous         ntpEnabled, interactive);
27420e6ea5dSraviteja-b }
27520e6ea5dSraviteja-b 
276ed4de7a8SEd Tanous // Redfish states that ip addresses can be
277ed4de7a8SEd Tanous // string, to set a value
278ed4de7a8SEd Tanous // null, to delete the value
279ed4de7a8SEd Tanous // object_t, empty json object, to ignore the value
280ed4de7a8SEd Tanous using IpAddress =
281ed4de7a8SEd Tanous     std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>;
282ed4de7a8SEd Tanous 
2834f48d5f6SEd Tanous inline void
284287ece64SGeorge Liu     handleNTPServersPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
285ed4de7a8SEd Tanous                           const std::vector<IpAddress>& ntpServerObjects,
286b9e15228SEd Tanous                           std::vector<std::string> currentNtpServers)
28720e6ea5dSraviteja-b {
288b9e15228SEd Tanous     std::vector<std::string>::iterator currentNtpServer =
289b9e15228SEd Tanous         currentNtpServers.begin();
290b9e15228SEd Tanous     for (size_t index = 0; index < ntpServerObjects.size(); index++)
291287ece64SGeorge Liu     {
292ed4de7a8SEd Tanous         const IpAddress& ntpServer = ntpServerObjects[index];
293ed4de7a8SEd Tanous         if (std::holds_alternative<std::nullptr_t>(ntpServer))
294b9e15228SEd Tanous         {
295b9e15228SEd Tanous             // Can't delete an item that doesn't exist
296b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
297b9e15228SEd Tanous             {
298bd79bce8SPatrick Williams                 messages::propertyValueNotInList(
299bd79bce8SPatrick Williams                     asyncResp->res, "null",
300bd79bce8SPatrick Williams                     "NTP/NTPServers/" + std::to_string(index));
301b9e15228SEd Tanous 
302287ece64SGeorge Liu                 return;
303287ece64SGeorge Liu             }
304b9e15228SEd Tanous             currentNtpServer = currentNtpServers.erase(currentNtpServer);
305b9e15228SEd Tanous             continue;
306b9e15228SEd Tanous         }
307b9e15228SEd Tanous         const nlohmann::json::object_t* ntpServerObject =
308ed4de7a8SEd Tanous             std::get_if<nlohmann::json::object_t>(&ntpServer);
309b9e15228SEd Tanous         if (ntpServerObject != nullptr)
310b9e15228SEd Tanous         {
311b9e15228SEd Tanous             if (!ntpServerObject->empty())
312b9e15228SEd Tanous             {
313ed4de7a8SEd Tanous                 messages::propertyValueNotInList(
314ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
315ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
316b9e15228SEd Tanous                 return;
317b9e15228SEd Tanous             }
318b9e15228SEd Tanous             // Can't retain an item that doesn't exist
319b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
320b9e15228SEd Tanous             {
321ed4de7a8SEd Tanous                 messages::propertyValueOutOfRange(
322ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
323ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
324b9e15228SEd Tanous 
325b9e15228SEd Tanous                 return;
326b9e15228SEd Tanous             }
327b9e15228SEd Tanous             // empty objects should leave the NtpServer unmodified
328b9e15228SEd Tanous             currentNtpServer++;
329b9e15228SEd Tanous             continue;
330b9e15228SEd Tanous         }
331b9e15228SEd Tanous 
332ed4de7a8SEd Tanous         const std::string* ntpServerStr = std::get_if<std::string>(&ntpServer);
333b9e15228SEd Tanous         if (ntpServerStr == nullptr)
334b9e15228SEd Tanous         {
335ed4de7a8SEd Tanous             messages::internalError(asyncResp->res);
336b9e15228SEd Tanous             return;
337b9e15228SEd Tanous         }
338b9e15228SEd Tanous         if (currentNtpServer == currentNtpServers.end())
339b9e15228SEd Tanous         {
340b9e15228SEd Tanous             // if we're at the end of the list, append to the end
341b9e15228SEd Tanous             currentNtpServers.push_back(*ntpServerStr);
342b9e15228SEd Tanous             currentNtpServer = currentNtpServers.end();
343b9e15228SEd Tanous             continue;
344b9e15228SEd Tanous         }
345b9e15228SEd Tanous         *currentNtpServer = *ntpServerStr;
346b9e15228SEd Tanous         currentNtpServer++;
347b9e15228SEd Tanous     }
348b9e15228SEd Tanous 
349b9e15228SEd Tanous     // Any remaining array elements should be removed
350b9e15228SEd Tanous     currentNtpServers.erase(currentNtpServer, currentNtpServers.end());
351287ece64SGeorge Liu 
352e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> ethInterfaces = {
353e99073f5SGeorge Liu         "xyz.openbmc_project.Network.EthernetInterface"};
354e99073f5SGeorge Liu     dbus::utility::getSubTree(
355e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, ethInterfaces,
356b9e15228SEd Tanous         [asyncResp, currentNtpServers](
3572138483cSGeorge Liu             const boost::system::error_code& ec,
358b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
3590a052baaSGeorge Liu             if (ec)
3600a052baaSGeorge Liu             {
36162598e31SEd Tanous                 BMCWEB_LOG_WARNING("D-Bus error: {}, {}", ec, ec.message());
3620a052baaSGeorge Liu                 messages::internalError(asyncResp->res);
3630a052baaSGeorge Liu                 return;
3640a052baaSGeorge Liu             }
3650a052baaSGeorge Liu 
3660a052baaSGeorge Liu             for (const auto& [objectPath, serviceMap] : subtree)
3670a052baaSGeorge Liu             {
3680a052baaSGeorge Liu                 for (const auto& [service, interfaces] : serviceMap)
3690a052baaSGeorge Liu                 {
3700a052baaSGeorge Liu                     for (const auto& interface : interfaces)
3710a052baaSGeorge Liu                     {
3720a052baaSGeorge Liu                         if (interface !=
3730a052baaSGeorge Liu                             "xyz.openbmc_project.Network.EthernetInterface")
3740a052baaSGeorge Liu                         {
3750a052baaSGeorge Liu                             continue;
3760a052baaSGeorge Liu                         }
3770a052baaSGeorge Liu 
378e93abac6SGinu George                         setDbusProperty(asyncResp, "NTP/NTPServers/", service,
379bd79bce8SPatrick Williams                                         objectPath, interface,
380bd79bce8SPatrick Williams                                         "StaticNTPServers", currentNtpServers);
38120e6ea5dSraviteja-b                     }
3820a052baaSGeorge Liu                 }
3830a052baaSGeorge Liu             }
384e99073f5SGeorge Liu         });
3850a052baaSGeorge Liu }
38620e6ea5dSraviteja-b 
3874f48d5f6SEd Tanous inline void
3884f48d5f6SEd Tanous     handleProtocolEnabled(const bool protocolEnabled,
389e5a99777SAlbert Zhang                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
39069320d54SJiaqing Zhao                           const std::string& netBasePath)
39167a78d87STom Joseph {
392e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
393e99073f5SGeorge Liu         "xyz.openbmc_project.Control.Service.Attributes"};
394e99073f5SGeorge Liu     dbus::utility::getSubTree(
395e99073f5SGeorge Liu         "/xyz/openbmc_project/control/service", 0, interfaces,
396e5a99777SAlbert Zhang         [protocolEnabled, asyncResp,
3972138483cSGeorge Liu          netBasePath](const boost::system::error_code& ec,
398b9d36b47SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
39967a78d87STom Joseph             if (ec)
40067a78d87STom Joseph             {
40167a78d87STom Joseph                 messages::internalError(asyncResp->res);
40267a78d87STom Joseph                 return;
40367a78d87STom Joseph             }
40467a78d87STom Joseph 
40567a78d87STom Joseph             for (const auto& entry : subtree)
40667a78d87STom Joseph             {
40718f8f608SEd Tanous                 if (entry.first.starts_with(netBasePath))
40867a78d87STom Joseph                 {
40987c44966SAsmitha Karunanithi                     setDbusProperty(
410e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
411e93abac6SGinu George                         entry.second.begin()->first, entry.first,
412bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
413bd79bce8SPatrick Williams                         "Running", protocolEnabled);
41487c44966SAsmitha Karunanithi                     setDbusProperty(
415e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
416e93abac6SGinu George                         entry.second.begin()->first, entry.first,
417bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
418bd79bce8SPatrick Williams                         "Enabled", protocolEnabled);
41967a78d87STom Joseph                 }
42067a78d87STom Joseph             }
421e99073f5SGeorge Liu         });
42267a78d87STom Joseph }
42367a78d87STom Joseph 
4244f48d5f6SEd Tanous inline std::string getHostName()
425501be32bSraviteja-b {
4267e860f15SJohn Edward Broadbent     std::string hostName;
4278d1b46d7Szhanghch05 
428d3a9e084SEd Tanous     std::array<char, HOST_NAME_MAX> hostNameCStr{};
4297e860f15SJohn Edward Broadbent     if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0)
4307e860f15SJohn Edward Broadbent     {
4317e860f15SJohn Edward Broadbent         hostName = hostNameCStr.data();
4327e860f15SJohn Edward Broadbent     }
4337e860f15SJohn Edward Broadbent     return hostName;
4347e860f15SJohn Edward Broadbent }
4357e860f15SJohn Edward Broadbent 
4364f48d5f6SEd Tanous inline void
4374f48d5f6SEd Tanous     getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4387e860f15SJohn Edward Broadbent {
439deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
440deae6a78SEd Tanous         "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
441deae6a78SEd Tanous         "org.freedesktop.timedate1", "NTP",
4428e157735SEd Tanous         [asyncResp](const boost::system::error_code& ec, bool enabled) {
4438b24275dSEd Tanous             if (ec)
4447e860f15SJohn Edward Broadbent             {
4458e157735SEd Tanous                 BMCWEB_LOG_WARNING(
4468e157735SEd Tanous                     "Failed to get NTP status, assuming not supported");
4477e860f15SJohn Edward Broadbent                 return;
4487e860f15SJohn Edward Broadbent             }
4497e860f15SJohn Edward Broadbent 
4508e157735SEd Tanous             asyncResp->res.jsonValue["NTP"]["ProtocolEnabled"] = enabled;
4511e1e598dSJonathan Doman         });
4527e860f15SJohn Edward Broadbent }
4537e860f15SJohn Edward Broadbent 
4545c3e9272SAbhishek Patel inline std::string encodeServiceObjectPath(std::string_view serviceName)
45569320d54SJiaqing Zhao {
45669320d54SJiaqing Zhao     sdbusplus::message::object_path objPath(
45769320d54SJiaqing Zhao         "/xyz/openbmc_project/control/service");
45869320d54SJiaqing Zhao     objPath /= serviceName;
45969320d54SJiaqing Zhao     return objPath.str;
46069320d54SJiaqing Zhao }
46169320d54SJiaqing Zhao 
4620f55d946SEd Tanous inline void handleBmcNetworkProtocolHead(
463e9f71672SEd Tanous     crow::App& app, const crow::Request& req,
464e9f71672SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
465e9f71672SEd Tanous {
466e9f71672SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
467e9f71672SEd Tanous     {
468e9f71672SEd Tanous         return;
469e9f71672SEd Tanous     }
470e9f71672SEd Tanous     asyncResp->res.addHeader(
471e9f71672SEd Tanous         boost::beast::http::field::link,
472e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
473e9f71672SEd Tanous }
474e9f71672SEd Tanous 
475e634b34cSEd Tanous inline void handleManagersNetworkProtocolPatch(
476e634b34cSEd Tanous     App& app, const crow::Request& req,
477253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
478253f11b8SEd Tanous     const std::string& managerId)
4797e860f15SJohn Edward Broadbent {
4803ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
48145ca1b86SEd Tanous     {
48245ca1b86SEd Tanous         return;
48345ca1b86SEd Tanous     }
484253f11b8SEd Tanous 
485253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
486253f11b8SEd Tanous     {
487253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
488253f11b8SEd Tanous         return;
489253f11b8SEd Tanous     }
490253f11b8SEd Tanous 
491501be32bSraviteja-b     std::optional<std::string> newHostName;
492ed4de7a8SEd Tanous 
493ed4de7a8SEd Tanous     std::optional<std::vector<IpAddress>> ntpServerObjects;
4945f4c798dSJiaqing Zhao     std::optional<bool> ntpEnabled;
4955f4c798dSJiaqing Zhao     std::optional<bool> ipmiEnabled;
4965f4c798dSJiaqing Zhao     std::optional<bool> sshEnabled;
497501be32bSraviteja-b 
4985f4c798dSJiaqing Zhao     if (!json_util::readJsonPatch(
499afc474aeSMyung Bae             req, asyncResp->res, //
500afc474aeSMyung Bae             "HostName", newHostName, //
501afc474aeSMyung Bae             "NTP/NTPServers", ntpServerObjects, //
502afc474aeSMyung Bae             "NTP/ProtocolEnabled", ntpEnabled, //
503afc474aeSMyung Bae             "IPMI/ProtocolEnabled", ipmiEnabled, //
504afc474aeSMyung Bae             "SSH/ProtocolEnabled", sshEnabled //
505afc474aeSMyung Bae             ))
506501be32bSraviteja-b     {
507501be32bSraviteja-b         return;
508501be32bSraviteja-b     }
509cf05f9dcSJohnathan Mantey 
5108d1b46d7Szhanghch05     asyncResp->res.result(boost::beast::http::status::no_content);
511501be32bSraviteja-b     if (newHostName)
512501be32bSraviteja-b     {
5132db77d34SJohnathan Mantey         messages::propertyNotWritable(asyncResp->res, "HostName");
51444fad2aaSEd Tanous         return;
515cf05f9dcSJohnathan Mantey     }
516cf05f9dcSJohnathan Mantey 
51720e6ea5dSraviteja-b     if (ntpEnabled)
51820e6ea5dSraviteja-b     {
5198e157735SEd Tanous         handleNTPProtocolEnabled(asyncResp, *ntpEnabled);
52020e6ea5dSraviteja-b     }
521b9e15228SEd Tanous     if (ntpServerObjects)
52220e6ea5dSraviteja-b     {
523b9e15228SEd Tanous         getEthernetIfaceData(
524b9e15228SEd Tanous             [asyncResp, ntpServerObjects](
525e634b34cSEd Tanous                 const bool success, std::vector<std::string>& currentNtpServers,
5260eebcefbSJishnu CM                 const std::vector<std::string>& /*dynamicNtpServers*/,
527b9e15228SEd Tanous                 const std::vector<std::string>& /*domainNames*/) {
528b9e15228SEd Tanous                 if (!success)
529b9e15228SEd Tanous                 {
530b9e15228SEd Tanous                     messages::internalError(asyncResp->res);
531b9e15228SEd Tanous                     return;
532b9e15228SEd Tanous                 }
533b9e15228SEd Tanous                 handleNTPServersPatch(asyncResp, *ntpServerObjects,
534b9e15228SEd Tanous                                       std::move(currentNtpServers));
535b9e15228SEd Tanous             });
53620e6ea5dSraviteja-b     }
53767a78d87STom Joseph 
5385f4c798dSJiaqing Zhao     if (ipmiEnabled)
53967a78d87STom Joseph     {
540e5a99777SAlbert Zhang         handleProtocolEnabled(
5415f4c798dSJiaqing Zhao             *ipmiEnabled, asyncResp,
54269320d54SJiaqing Zhao             encodeServiceObjectPath(std::string(ipmiServiceName) + '@'));
543e5a99777SAlbert Zhang     }
544e5a99777SAlbert Zhang 
5455f4c798dSJiaqing Zhao     if (sshEnabled)
546e5a99777SAlbert Zhang     {
54769320d54SJiaqing Zhao         handleProtocolEnabled(*sshEnabled, asyncResp,
54869320d54SJiaqing Zhao                               encodeServiceObjectPath(sshServiceName));
54967a78d87STom Joseph     }
550e634b34cSEd Tanous }
551e634b34cSEd Tanous 
552af20dd1cSEd Tanous inline void handleManagersNetworkProtocolHead(
553e634b34cSEd Tanous     App& app, const crow::Request& req,
554253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
555253f11b8SEd Tanous     const std::string& managerId)
556e634b34cSEd Tanous {
557e634b34cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
558e634b34cSEd Tanous     {
559e634b34cSEd Tanous         return;
560e634b34cSEd Tanous     }
561af20dd1cSEd Tanous     asyncResp->res.addHeader(
562af20dd1cSEd Tanous         boost::beast::http::field::link,
563af20dd1cSEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
564253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
565253f11b8SEd Tanous     {
566253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
567253f11b8SEd Tanous         return;
568253f11b8SEd Tanous     }
569af20dd1cSEd Tanous }
570af20dd1cSEd Tanous 
571af20dd1cSEd Tanous inline void handleManagersNetworkProtocolGet(
572af20dd1cSEd Tanous     App& app, const crow::Request& req,
573253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
574253f11b8SEd Tanous     const std::string& managerId)
575af20dd1cSEd Tanous {
576253f11b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
577253f11b8SEd Tanous     {
578253f11b8SEd Tanous         return;
579253f11b8SEd Tanous     }
580253f11b8SEd Tanous     asyncResp->res.addHeader(
581253f11b8SEd Tanous         boost::beast::http::field::link,
582253f11b8SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
583253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
584253f11b8SEd Tanous     {
585253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
586253f11b8SEd Tanous         return;
587253f11b8SEd Tanous     }
588253f11b8SEd Tanous 
589e634b34cSEd Tanous     getNetworkData(asyncResp, req);
590e634b34cSEd Tanous }
591e634b34cSEd Tanous 
592e634b34cSEd Tanous inline void requestRoutesNetworkProtocol(App& app)
593e634b34cSEd Tanous {
594253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
595e634b34cSEd Tanous         .privileges(redfish::privileges::patchManagerNetworkProtocol)
596e634b34cSEd Tanous         .methods(boost::beast::http::verb::patch)(
597e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolPatch, std::ref(app)));
5987e860f15SJohn Edward Broadbent 
599253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
600e9f71672SEd Tanous         .privileges(redfish::privileges::headManagerNetworkProtocol)
601e9f71672SEd Tanous         .methods(boost::beast::http::verb::head)(
602af20dd1cSEd Tanous             std::bind_front(handleManagersNetworkProtocolHead, std::ref(app)));
603e9f71672SEd Tanous 
604253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
605ed398213SEd Tanous         .privileges(redfish::privileges::getManagerNetworkProtocol)
6067e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
607e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolGet, std::ref(app)));
608cf05f9dcSJohnathan Mantey }
60970141561SBorawski.Lukasz 
61070141561SBorawski.Lukasz } // namespace redfish
611