xref: /openbmc/bmcweb/features/redfish/lib/network_protocol.hpp (revision 504af5a0568171b72caf13234cc81380b261fa21)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
470141561SBorawski.Lukasz #pragma once
570141561SBorawski.Lukasz 
6d7857201SEd Tanous #include "bmcweb_config.h"
7d7857201SEd Tanous 
83ccb3adbSEd Tanous #include "app.hpp"
9d7857201SEd Tanous #include "async_resp.hpp"
10d7857201SEd Tanous #include "dbus_singleton.hpp"
113ccb3adbSEd Tanous #include "dbus_utility.hpp"
123a8a0088SKowalski, Kamil #include "error_messages.hpp"
13539d8c6bSEd Tanous #include "generated/enums/resource.hpp"
14d7857201SEd Tanous #include "http_request.hpp"
15d7857201SEd Tanous #include "logging.hpp"
16d7857201SEd Tanous #include "privileges.hpp"
173ccb3adbSEd Tanous #include "query.hpp"
18b4bec66bSAbhishek Patel #include "redfish_util.hpp"
193ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
20d7857201SEd Tanous #include "utils/dbus_utils.hpp"
213ccb3adbSEd Tanous #include "utils/json_utils.hpp"
223ccb3adbSEd Tanous #include "utils/stl_utils.hpp"
2370141561SBorawski.Lukasz 
24d7857201SEd Tanous #include <unistd.h>
25d7857201SEd Tanous 
26d7857201SEd Tanous #include <boost/beast/http/field.hpp>
27d7857201SEd Tanous #include <boost/beast/http/status.hpp>
28d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
29e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
30253f11b8SEd Tanous #include <boost/url/format.hpp>
31d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
321214b7e7SGunnar Mills 
33e99073f5SGeorge Liu #include <array>
34d7857201SEd Tanous #include <cstddef>
35d7857201SEd Tanous #include <functional>
36d7857201SEd Tanous #include <memory>
371214b7e7SGunnar Mills #include <optional>
38d7857201SEd Tanous #include <string>
39e99073f5SGeorge Liu #include <string_view>
40d7857201SEd Tanous #include <tuple>
41d7857201SEd Tanous #include <utility>
42abf2add6SEd Tanous #include <variant>
430eebcefbSJishnu CM #include <vector>
445f4c798dSJiaqing Zhao 
451abe55efSEd Tanous namespace redfish
461abe55efSEd Tanous {
4770141561SBorawski.Lukasz 
487e860f15SJohn Edward Broadbent void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
497e860f15SJohn Edward Broadbent std::string getHostName();
507e860f15SJohn Edward Broadbent 
515c3e9272SAbhishek Patel static constexpr std::string_view sshServiceName = "dropbear";
525c3e9272SAbhishek Patel static constexpr std::string_view httpsServiceName = "bmcweb";
535c3e9272SAbhishek Patel static constexpr std::string_view ipmiServiceName = "phosphor-ipmi-net";
545c3e9272SAbhishek Patel 
555c3e9272SAbhishek Patel // Mapping from Redfish NetworkProtocol key name to backend service that hosts
565c3e9272SAbhishek Patel // that protocol.
575c3e9272SAbhishek Patel static constexpr std::array<std::pair<std::string_view, std::string_view>, 3>
585c3e9272SAbhishek Patel     networkProtocolToDbus = {{{"SSH", sshServiceName},
5969320d54SJiaqing Zhao                               {"HTTPS", httpsServiceName},
6069320d54SJiaqing Zhao                               {"IPMI", ipmiServiceName}}};
613a8a0088SKowalski, Kamil 
62711ac7a9SEd Tanous inline void extractNTPServersAndDomainNamesData(
63711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType& dbusData,
640eebcefbSJishnu CM     std::vector<std::string>& ntpData, std::vector<std::string>& dynamicNtpData,
650eebcefbSJishnu CM     std::vector<std::string>& dnData)
6620e6ea5dSraviteja-b {
6781ce609eSEd Tanous     for (const auto& obj : dbusData)
6820e6ea5dSraviteja-b     {
6920e6ea5dSraviteja-b         for (const auto& ifacePair : obj.second)
7020e6ea5dSraviteja-b         {
710a052baaSGeorge Liu             if (ifacePair.first !=
7220e6ea5dSraviteja-b                 "xyz.openbmc_project.Network.EthernetInterface")
7320e6ea5dSraviteja-b             {
740a052baaSGeorge Liu                 continue;
750a052baaSGeorge Liu             }
760a052baaSGeorge Liu 
7720e6ea5dSraviteja-b             for (const auto& propertyPair : ifacePair.second)
7820e6ea5dSraviteja-b             {
79fcd2682aSEd Tanous                 if (propertyPair.first == "StaticNTPServers")
8020e6ea5dSraviteja-b                 {
8120e6ea5dSraviteja-b                     const std::vector<std::string>* ntpServers =
828d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
8320e6ea5dSraviteja-b                             &propertyPair.second);
8420e6ea5dSraviteja-b                     if (ntpServers != nullptr)
8520e6ea5dSraviteja-b                     {
86c251fe81SJian Zhang                         ntpData.insert(ntpData.end(), ntpServers->begin(),
87c251fe81SJian Zhang                                        ntpServers->end());
8820e6ea5dSraviteja-b                     }
8920e6ea5dSraviteja-b                 }
900eebcefbSJishnu CM                 else if (propertyPair.first == "NTPServers")
910eebcefbSJishnu CM                 {
920eebcefbSJishnu CM                     const std::vector<std::string>* dynamicNtpServers =
930eebcefbSJishnu CM                         std::get_if<std::vector<std::string>>(
940eebcefbSJishnu CM                             &propertyPair.second);
950eebcefbSJishnu CM                     if (dynamicNtpServers != nullptr)
960eebcefbSJishnu CM                     {
970eebcefbSJishnu CM                         dynamicNtpData = *dynamicNtpServers;
980eebcefbSJishnu CM                     }
990eebcefbSJishnu CM                 }
100d24bfc7aSJennifer Lee                 else if (propertyPair.first == "DomainName")
101d24bfc7aSJennifer Lee                 {
102d24bfc7aSJennifer Lee                     const std::vector<std::string>* domainNames =
1038d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
104d24bfc7aSJennifer Lee                             &propertyPair.second);
105d24bfc7aSJennifer Lee                     if (domainNames != nullptr)
106d24bfc7aSJennifer Lee                     {
107c251fe81SJian Zhang                         dnData.insert(dnData.end(), domainNames->begin(),
108c251fe81SJian Zhang                                       domainNames->end());
109d24bfc7aSJennifer Lee                     }
110d24bfc7aSJennifer Lee                 }
11120e6ea5dSraviteja-b             }
11220e6ea5dSraviteja-b         }
11320e6ea5dSraviteja-b     }
1140225b87bSEd Tanous     stl_utils::removeDuplicate(ntpData);
115c251fe81SJian Zhang     stl_utils::removeDuplicate(dnData);
11620e6ea5dSraviteja-b }
11720e6ea5dSraviteja-b 
11820e6ea5dSraviteja-b template <typename CallbackFunc>
11920e6ea5dSraviteja-b void getEthernetIfaceData(CallbackFunc&& callback)
12020e6ea5dSraviteja-b {
1215eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1225eb468daSGeorge Liu     dbus::utility::getManagedObjects(
1235eb468daSGeorge Liu         "xyz.openbmc_project.Network", path,
1248cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback)](
1258b24275dSEd Tanous             const boost::system::error_code& ec,
126711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& dbusData) {
12720e6ea5dSraviteja-b             std::vector<std::string> ntpServers;
1280eebcefbSJishnu CM             std::vector<std::string> dynamicNtpServers;
129d24bfc7aSJennifer Lee             std::vector<std::string> domainNames;
13020e6ea5dSraviteja-b 
1318b24275dSEd Tanous             if (ec)
13220e6ea5dSraviteja-b             {
1330eebcefbSJishnu CM                 callback(false, ntpServers, dynamicNtpServers, domainNames);
13420e6ea5dSraviteja-b                 return;
13520e6ea5dSraviteja-b             }
13620e6ea5dSraviteja-b 
137bd79bce8SPatrick Williams             extractNTPServersAndDomainNamesData(dbusData, ntpServers,
1380eebcefbSJishnu CM                                                 dynamicNtpServers, domainNames);
13920e6ea5dSraviteja-b 
1400eebcefbSJishnu CM             callback(true, ntpServers, dynamicNtpServers, domainNames);
1415eb468daSGeorge Liu         });
142271584abSEd Tanous }
14320e6ea5dSraviteja-b 
1445c3e9272SAbhishek Patel inline void afterNetworkPortRequest(
1455c3e9272SAbhishek Patel     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1465c3e9272SAbhishek Patel     const boost::system::error_code& ec,
1475c3e9272SAbhishek Patel     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
1485c3e9272SAbhishek Patel {
1495c3e9272SAbhishek Patel     if (ec)
1505c3e9272SAbhishek Patel     {
1515c3e9272SAbhishek Patel         messages::internalError(asyncResp->res);
1525c3e9272SAbhishek Patel         return;
1535c3e9272SAbhishek Patel     }
1545c3e9272SAbhishek Patel     for (const auto& data : socketData)
1555c3e9272SAbhishek Patel     {
1565c3e9272SAbhishek Patel         const std::string& socketPath = get<0>(data);
1575c3e9272SAbhishek Patel         const std::string& protocolName = get<1>(data);
1585c3e9272SAbhishek Patel         bool isProtocolEnabled = get<2>(data);
1595c3e9272SAbhishek Patel 
1605c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
1615c3e9272SAbhishek Patel             isProtocolEnabled;
1625c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["Port"] = nullptr;
1635c3e9272SAbhishek Patel         getPortNumber(socketPath, [asyncResp, protocolName](
1645c3e9272SAbhishek Patel                                       const boost::system::error_code& ec2,
1655c3e9272SAbhishek Patel                                       int portNumber) {
1665c3e9272SAbhishek Patel             if (ec2)
1675c3e9272SAbhishek Patel             {
1685c3e9272SAbhishek Patel                 messages::internalError(asyncResp->res);
1695c3e9272SAbhishek Patel                 return;
1705c3e9272SAbhishek Patel             }
1715c3e9272SAbhishek Patel             asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
1725c3e9272SAbhishek Patel         });
1735c3e9272SAbhishek Patel     }
1745c3e9272SAbhishek Patel }
1755c3e9272SAbhishek Patel 
1764f48d5f6SEd Tanous inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
17772048780SAbhishek Patel                            const crow::Request& req)
1781abe55efSEd Tanous {
1793e72c202SNinad Palsule     if (req.session == nullptr)
1803e72c202SNinad Palsule     {
1813e72c202SNinad Palsule         messages::internalError(asyncResp->res);
1823e72c202SNinad Palsule         return;
1833e72c202SNinad Palsule     }
1843e72c202SNinad Palsule 
185e9f71672SEd Tanous     asyncResp->res.addHeader(
186e9f71672SEd Tanous         boost::beast::http::field::link,
187e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/NetworkProtocol.json>; rel=describedby");
1880f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
1890eebcefbSJishnu CM         "#ManagerNetworkProtocol.v1_9_0.ManagerNetworkProtocol";
1900f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
191253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
192253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
1930f74e643SEd Tanous     asyncResp->res.jsonValue["Id"] = "NetworkProtocol";
1940f74e643SEd Tanous     asyncResp->res.jsonValue["Name"] = "Manager Network Protocol";
1950f74e643SEd Tanous     asyncResp->res.jsonValue["Description"] = "Manager Network Service";
196539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
197539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["HealthRollup"] = resource::Health::OK;
198539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
1990f74e643SEd Tanous 
20061932318SXiaochao Ma     // HTTP is Mandatory attribute as per OCP Baseline Profile - v1.0.0,
201818ea7b8SJoshi-Mansi     // but from security perspective it is not recommended to use.
202818ea7b8SJoshi-Mansi     // Hence using protocolEnabled as false to make it OCP and security-wise
203818ea7b8SJoshi-Mansi     // compliant
2045c3e9272SAbhishek Patel     asyncResp->res.jsonValue["HTTP"]["Port"] = nullptr;
205818ea7b8SJoshi-Mansi     asyncResp->res.jsonValue["HTTP"]["ProtocolEnabled"] = false;
206818ea7b8SJoshi-Mansi 
2071ee2db7fSAndrew Geissler     // The ProtocolEnabled of the following protocols is determined by
2081ee2db7fSAndrew Geissler     // inspecting the state of associated systemd sockets. If these protocols
2091ee2db7fSAndrew Geissler     // have been disabled, then the systemd socket unit files will not be found
2101ee2db7fSAndrew Geissler     // and the protocols will not be returned in this Redfish query. Set some
2111ee2db7fSAndrew Geissler     // defaults to ensure something is always returned.
2121ee2db7fSAndrew Geissler     for (const auto& nwkProtocol : networkProtocolToDbus)
2131ee2db7fSAndrew Geissler     {
2141ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["Port"] = nullptr;
2151ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["ProtocolEnabled"] = false;
2161ee2db7fSAndrew Geissler     }
2171ee2db7fSAndrew Geissler 
218d24bfc7aSJennifer Lee     std::string hostName = getHostName();
219d24bfc7aSJennifer Lee 
220d24bfc7aSJennifer Lee     asyncResp->res.jsonValue["HostName"] = hostName;
2213a8a0088SKowalski, Kamil 
22220e6ea5dSraviteja-b     getNTPProtocolEnabled(asyncResp);
22320e6ea5dSraviteja-b 
224bd79bce8SPatrick Williams     getEthernetIfaceData([hostName, asyncResp](
225bd79bce8SPatrick Williams                              const bool& success,
22602cad96eSEd Tanous                              const std::vector<std::string>& ntpServers,
2270eebcefbSJishnu CM                              const std::vector<std::string>& dynamicNtpServers,
228d24bfc7aSJennifer Lee                              const std::vector<std::string>& domainNames) {
22920e6ea5dSraviteja-b         if (!success)
23020e6ea5dSraviteja-b         {
2310a052baaSGeorge Liu             messages::resourceNotFound(asyncResp->res, "ManagerNetworkProtocol",
2320a052baaSGeorge Liu                                        "NetworkProtocol");
23320e6ea5dSraviteja-b             return;
23420e6ea5dSraviteja-b         }
23520e6ea5dSraviteja-b         asyncResp->res.jsonValue["NTP"]["NTPServers"] = ntpServers;
2360eebcefbSJishnu CM         asyncResp->res.jsonValue["NTP"]["NetworkSuppliedServers"] =
2370eebcefbSJishnu CM             dynamicNtpServers;
23826f6976fSEd Tanous         if (!hostName.empty())
239d24bfc7aSJennifer Lee         {
240f23b7296SEd Tanous             std::string fqdn = hostName;
24126f6976fSEd Tanous             if (!domainNames.empty())
242d24bfc7aSJennifer Lee             {
243f23b7296SEd Tanous                 fqdn += ".";
244f23b7296SEd Tanous                 fqdn += domainNames[0];
245d24bfc7aSJennifer Lee             }
2462c70f800SEd Tanous             asyncResp->res.jsonValue["FQDN"] = std::move(fqdn);
247d24bfc7aSJennifer Lee         }
24820e6ea5dSraviteja-b     });
24920e6ea5dSraviteja-b 
25072048780SAbhishek Patel     Privileges effectiveUserPrivileges =
2513e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
25272048780SAbhishek Patel 
25372048780SAbhishek Patel     // /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
25472048780SAbhishek Patel     // something only ConfigureManager can access then only display when
25572048780SAbhishek Patel     // the user has permissions ConfigureManager
25672048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
25772048780SAbhishek Patel                                          effectiveUserPrivileges))
25872048780SAbhishek Patel     {
2591476687dSEd Tanous         asyncResp->res.jsonValue["HTTPS"]["Certificates"]["@odata.id"] =
260253f11b8SEd Tanous             boost::urls::format(
261253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
262253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
26370141561SBorawski.Lukasz     }
26470141561SBorawski.Lukasz 
2655c3e9272SAbhishek Patel     getPortStatusAndPath(std::span(networkProtocolToDbus),
2665c3e9272SAbhishek Patel                          std::bind_front(afterNetworkPortRequest, asyncResp));
267b4bec66bSAbhishek Patel } // namespace redfish
268501be32bSraviteja-b 
2698e157735SEd Tanous inline void afterSetNTP(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2708e157735SEd Tanous                         const boost::system::error_code& ec)
27120e6ea5dSraviteja-b {
2728e157735SEd Tanous     if (ec)
27320e6ea5dSraviteja-b     {
2748e157735SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
2758e157735SEd Tanous                          ec);
2768e157735SEd Tanous         messages::internalError(asyncResp->res);
2778e157735SEd Tanous         return;
27820e6ea5dSraviteja-b     }
2798e157735SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
28020e6ea5dSraviteja-b }
28120e6ea5dSraviteja-b 
2828e157735SEd Tanous inline void handleNTPProtocolEnabled(
2838e157735SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool ntpEnabled)
2848e157735SEd Tanous {
2858e157735SEd Tanous     bool interactive = false;
2868e157735SEd Tanous     auto callback = [asyncResp](const boost::system::error_code& ec) {
2878e157735SEd Tanous         afterSetNTP(asyncResp, ec);
2888e157735SEd Tanous     };
2898e157735SEd Tanous     crow::connections::systemBus->async_method_call(
2908e157735SEd Tanous         std::move(callback), "org.freedesktop.timedate1",
2918e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP",
2928e157735SEd Tanous         ntpEnabled, interactive);
29320e6ea5dSraviteja-b }
29420e6ea5dSraviteja-b 
295ed4de7a8SEd Tanous // Redfish states that ip addresses can be
296ed4de7a8SEd Tanous // string, to set a value
297ed4de7a8SEd Tanous // null, to delete the value
298ed4de7a8SEd Tanous // object_t, empty json object, to ignore the value
299ed4de7a8SEd Tanous using IpAddress =
300ed4de7a8SEd Tanous     std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>;
301ed4de7a8SEd Tanous 
302*504af5a0SPatrick Williams inline void handleNTPServersPatch(
303*504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
304ed4de7a8SEd Tanous     const std::vector<IpAddress>& ntpServerObjects,
305b9e15228SEd Tanous     std::vector<std::string> currentNtpServers)
30620e6ea5dSraviteja-b {
307b9e15228SEd Tanous     std::vector<std::string>::iterator currentNtpServer =
308b9e15228SEd Tanous         currentNtpServers.begin();
309b9e15228SEd Tanous     for (size_t index = 0; index < ntpServerObjects.size(); index++)
310287ece64SGeorge Liu     {
311ed4de7a8SEd Tanous         const IpAddress& ntpServer = ntpServerObjects[index];
312ed4de7a8SEd Tanous         if (std::holds_alternative<std::nullptr_t>(ntpServer))
313b9e15228SEd Tanous         {
314b9e15228SEd Tanous             // Can't delete an item that doesn't exist
315b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
316b9e15228SEd Tanous             {
317bd79bce8SPatrick Williams                 messages::propertyValueNotInList(
318bd79bce8SPatrick Williams                     asyncResp->res, "null",
319bd79bce8SPatrick Williams                     "NTP/NTPServers/" + std::to_string(index));
320b9e15228SEd Tanous 
321287ece64SGeorge Liu                 return;
322287ece64SGeorge Liu             }
323b9e15228SEd Tanous             currentNtpServer = currentNtpServers.erase(currentNtpServer);
324b9e15228SEd Tanous             continue;
325b9e15228SEd Tanous         }
326b9e15228SEd Tanous         const nlohmann::json::object_t* ntpServerObject =
327ed4de7a8SEd Tanous             std::get_if<nlohmann::json::object_t>(&ntpServer);
328b9e15228SEd Tanous         if (ntpServerObject != nullptr)
329b9e15228SEd Tanous         {
330b9e15228SEd Tanous             if (!ntpServerObject->empty())
331b9e15228SEd Tanous             {
332ed4de7a8SEd Tanous                 messages::propertyValueNotInList(
333ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
334ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
335b9e15228SEd Tanous                 return;
336b9e15228SEd Tanous             }
337b9e15228SEd Tanous             // Can't retain an item that doesn't exist
338b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
339b9e15228SEd Tanous             {
340ed4de7a8SEd Tanous                 messages::propertyValueOutOfRange(
341ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
342ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
343b9e15228SEd Tanous 
344b9e15228SEd Tanous                 return;
345b9e15228SEd Tanous             }
346b9e15228SEd Tanous             // empty objects should leave the NtpServer unmodified
347b9e15228SEd Tanous             currentNtpServer++;
348b9e15228SEd Tanous             continue;
349b9e15228SEd Tanous         }
350b9e15228SEd Tanous 
351ed4de7a8SEd Tanous         const std::string* ntpServerStr = std::get_if<std::string>(&ntpServer);
352b9e15228SEd Tanous         if (ntpServerStr == nullptr)
353b9e15228SEd Tanous         {
354ed4de7a8SEd Tanous             messages::internalError(asyncResp->res);
355b9e15228SEd Tanous             return;
356b9e15228SEd Tanous         }
357b9e15228SEd Tanous         if (currentNtpServer == currentNtpServers.end())
358b9e15228SEd Tanous         {
359b9e15228SEd Tanous             // if we're at the end of the list, append to the end
360b9e15228SEd Tanous             currentNtpServers.push_back(*ntpServerStr);
361b9e15228SEd Tanous             currentNtpServer = currentNtpServers.end();
362b9e15228SEd Tanous             continue;
363b9e15228SEd Tanous         }
364b9e15228SEd Tanous         *currentNtpServer = *ntpServerStr;
365b9e15228SEd Tanous         currentNtpServer++;
366b9e15228SEd Tanous     }
367b9e15228SEd Tanous 
368b9e15228SEd Tanous     // Any remaining array elements should be removed
369b9e15228SEd Tanous     currentNtpServers.erase(currentNtpServer, currentNtpServers.end());
370287ece64SGeorge Liu 
371e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> ethInterfaces = {
372e99073f5SGeorge Liu         "xyz.openbmc_project.Network.EthernetInterface"};
373e99073f5SGeorge Liu     dbus::utility::getSubTree(
374e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, ethInterfaces,
375b9e15228SEd Tanous         [asyncResp, currentNtpServers](
3762138483cSGeorge Liu             const boost::system::error_code& ec,
377b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
3780a052baaSGeorge Liu             if (ec)
3790a052baaSGeorge Liu             {
38062598e31SEd Tanous                 BMCWEB_LOG_WARNING("D-Bus error: {}, {}", ec, ec.message());
3810a052baaSGeorge Liu                 messages::internalError(asyncResp->res);
3820a052baaSGeorge Liu                 return;
3830a052baaSGeorge Liu             }
3840a052baaSGeorge Liu 
3850a052baaSGeorge Liu             for (const auto& [objectPath, serviceMap] : subtree)
3860a052baaSGeorge Liu             {
3870a052baaSGeorge Liu                 for (const auto& [service, interfaces] : serviceMap)
3880a052baaSGeorge Liu                 {
3890a052baaSGeorge Liu                     for (const auto& interface : interfaces)
3900a052baaSGeorge Liu                     {
3910a052baaSGeorge Liu                         if (interface !=
3920a052baaSGeorge Liu                             "xyz.openbmc_project.Network.EthernetInterface")
3930a052baaSGeorge Liu                         {
3940a052baaSGeorge Liu                             continue;
3950a052baaSGeorge Liu                         }
3960a052baaSGeorge Liu 
397e93abac6SGinu George                         setDbusProperty(asyncResp, "NTP/NTPServers/", service,
398bd79bce8SPatrick Williams                                         objectPath, interface,
399bd79bce8SPatrick Williams                                         "StaticNTPServers", currentNtpServers);
40020e6ea5dSraviteja-b                     }
4010a052baaSGeorge Liu                 }
4020a052baaSGeorge Liu             }
403e99073f5SGeorge Liu         });
4040a052baaSGeorge Liu }
40520e6ea5dSraviteja-b 
406*504af5a0SPatrick Williams inline void handleProtocolEnabled(
407*504af5a0SPatrick Williams     const bool protocolEnabled,
408e5a99777SAlbert Zhang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40969320d54SJiaqing Zhao     const std::string& netBasePath)
41067a78d87STom Joseph {
411e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
412e99073f5SGeorge Liu         "xyz.openbmc_project.Control.Service.Attributes"};
413e99073f5SGeorge Liu     dbus::utility::getSubTree(
414e99073f5SGeorge Liu         "/xyz/openbmc_project/control/service", 0, interfaces,
415e5a99777SAlbert Zhang         [protocolEnabled, asyncResp,
4162138483cSGeorge Liu          netBasePath](const boost::system::error_code& ec,
417b9d36b47SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
41867a78d87STom Joseph             if (ec)
41967a78d87STom Joseph             {
42067a78d87STom Joseph                 messages::internalError(asyncResp->res);
42167a78d87STom Joseph                 return;
42267a78d87STom Joseph             }
42367a78d87STom Joseph 
42467a78d87STom Joseph             for (const auto& entry : subtree)
42567a78d87STom Joseph             {
42618f8f608SEd Tanous                 if (entry.first.starts_with(netBasePath))
42767a78d87STom Joseph                 {
42887c44966SAsmitha Karunanithi                     setDbusProperty(
429e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
430e93abac6SGinu George                         entry.second.begin()->first, entry.first,
431bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
432bd79bce8SPatrick Williams                         "Running", protocolEnabled);
43387c44966SAsmitha Karunanithi                     setDbusProperty(
434e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
435e93abac6SGinu George                         entry.second.begin()->first, entry.first,
436bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
437bd79bce8SPatrick Williams                         "Enabled", protocolEnabled);
43867a78d87STom Joseph                 }
43967a78d87STom Joseph             }
440e99073f5SGeorge Liu         });
44167a78d87STom Joseph }
44267a78d87STom Joseph 
4434f48d5f6SEd Tanous inline std::string getHostName()
444501be32bSraviteja-b {
4457e860f15SJohn Edward Broadbent     std::string hostName;
4468d1b46d7Szhanghch05 
447d3a9e084SEd Tanous     std::array<char, HOST_NAME_MAX> hostNameCStr{};
4487e860f15SJohn Edward Broadbent     if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0)
4497e860f15SJohn Edward Broadbent     {
4507e860f15SJohn Edward Broadbent         hostName = hostNameCStr.data();
4517e860f15SJohn Edward Broadbent     }
4527e860f15SJohn Edward Broadbent     return hostName;
4537e860f15SJohn Edward Broadbent }
4547e860f15SJohn Edward Broadbent 
455*504af5a0SPatrick Williams inline void getNTPProtocolEnabled(
456*504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4577e860f15SJohn Edward Broadbent {
458deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
459deae6a78SEd Tanous         "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
460deae6a78SEd Tanous         "org.freedesktop.timedate1", "NTP",
4618e157735SEd Tanous         [asyncResp](const boost::system::error_code& ec, bool enabled) {
4628b24275dSEd Tanous             if (ec)
4637e860f15SJohn Edward Broadbent             {
4648e157735SEd Tanous                 BMCWEB_LOG_WARNING(
4658e157735SEd Tanous                     "Failed to get NTP status, assuming not supported");
4667e860f15SJohn Edward Broadbent                 return;
4677e860f15SJohn Edward Broadbent             }
4687e860f15SJohn Edward Broadbent 
4698e157735SEd Tanous             asyncResp->res.jsonValue["NTP"]["ProtocolEnabled"] = enabled;
4701e1e598dSJonathan Doman         });
4717e860f15SJohn Edward Broadbent }
4727e860f15SJohn Edward Broadbent 
4735c3e9272SAbhishek Patel inline std::string encodeServiceObjectPath(std::string_view serviceName)
47469320d54SJiaqing Zhao {
47569320d54SJiaqing Zhao     sdbusplus::message::object_path objPath(
47669320d54SJiaqing Zhao         "/xyz/openbmc_project/control/service");
47769320d54SJiaqing Zhao     objPath /= serviceName;
47869320d54SJiaqing Zhao     return objPath.str;
47969320d54SJiaqing Zhao }
48069320d54SJiaqing Zhao 
4810f55d946SEd Tanous inline void handleBmcNetworkProtocolHead(
482e9f71672SEd Tanous     crow::App& app, const crow::Request& req,
483e9f71672SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
484e9f71672SEd Tanous {
485e9f71672SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
486e9f71672SEd Tanous     {
487e9f71672SEd Tanous         return;
488e9f71672SEd Tanous     }
489e9f71672SEd Tanous     asyncResp->res.addHeader(
490e9f71672SEd Tanous         boost::beast::http::field::link,
491e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
492e9f71672SEd Tanous }
493e9f71672SEd Tanous 
494e634b34cSEd Tanous inline void handleManagersNetworkProtocolPatch(
495e634b34cSEd Tanous     App& app, const crow::Request& req,
496253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
497253f11b8SEd Tanous     const std::string& managerId)
4987e860f15SJohn Edward Broadbent {
4993ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
50045ca1b86SEd Tanous     {
50145ca1b86SEd Tanous         return;
50245ca1b86SEd Tanous     }
503253f11b8SEd Tanous 
504253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
505253f11b8SEd Tanous     {
506253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
507253f11b8SEd Tanous         return;
508253f11b8SEd Tanous     }
509253f11b8SEd Tanous 
510501be32bSraviteja-b     std::optional<std::string> newHostName;
511ed4de7a8SEd Tanous 
512ed4de7a8SEd Tanous     std::optional<std::vector<IpAddress>> ntpServerObjects;
5135f4c798dSJiaqing Zhao     std::optional<bool> ntpEnabled;
5145f4c798dSJiaqing Zhao     std::optional<bool> ipmiEnabled;
5155f4c798dSJiaqing Zhao     std::optional<bool> sshEnabled;
516501be32bSraviteja-b 
5175f4c798dSJiaqing Zhao     if (!json_util::readJsonPatch(
518afc474aeSMyung Bae             req, asyncResp->res,                 //
519afc474aeSMyung Bae             "HostName", newHostName,             //
520afc474aeSMyung Bae             "NTP/NTPServers", ntpServerObjects,  //
521afc474aeSMyung Bae             "NTP/ProtocolEnabled", ntpEnabled,   //
522afc474aeSMyung Bae             "IPMI/ProtocolEnabled", ipmiEnabled, //
523afc474aeSMyung Bae             "SSH/ProtocolEnabled", sshEnabled    //
524afc474aeSMyung Bae             ))
525501be32bSraviteja-b     {
526501be32bSraviteja-b         return;
527501be32bSraviteja-b     }
528cf05f9dcSJohnathan Mantey 
5298d1b46d7Szhanghch05     asyncResp->res.result(boost::beast::http::status::no_content);
530501be32bSraviteja-b     if (newHostName)
531501be32bSraviteja-b     {
5322db77d34SJohnathan Mantey         messages::propertyNotWritable(asyncResp->res, "HostName");
53344fad2aaSEd Tanous         return;
534cf05f9dcSJohnathan Mantey     }
535cf05f9dcSJohnathan Mantey 
53620e6ea5dSraviteja-b     if (ntpEnabled)
53720e6ea5dSraviteja-b     {
5388e157735SEd Tanous         handleNTPProtocolEnabled(asyncResp, *ntpEnabled);
53920e6ea5dSraviteja-b     }
540b9e15228SEd Tanous     if (ntpServerObjects)
54120e6ea5dSraviteja-b     {
542b9e15228SEd Tanous         getEthernetIfaceData(
543b9e15228SEd Tanous             [asyncResp, ntpServerObjects](
544e634b34cSEd Tanous                 const bool success, std::vector<std::string>& currentNtpServers,
5450eebcefbSJishnu CM                 const std::vector<std::string>& /*dynamicNtpServers*/,
546b9e15228SEd Tanous                 const std::vector<std::string>& /*domainNames*/) {
547b9e15228SEd Tanous                 if (!success)
548b9e15228SEd Tanous                 {
549b9e15228SEd Tanous                     messages::internalError(asyncResp->res);
550b9e15228SEd Tanous                     return;
551b9e15228SEd Tanous                 }
552b9e15228SEd Tanous                 handleNTPServersPatch(asyncResp, *ntpServerObjects,
553b9e15228SEd Tanous                                       std::move(currentNtpServers));
554b9e15228SEd Tanous             });
55520e6ea5dSraviteja-b     }
55667a78d87STom Joseph 
5575f4c798dSJiaqing Zhao     if (ipmiEnabled)
55867a78d87STom Joseph     {
559e5a99777SAlbert Zhang         handleProtocolEnabled(
5605f4c798dSJiaqing Zhao             *ipmiEnabled, asyncResp,
56169320d54SJiaqing Zhao             encodeServiceObjectPath(std::string(ipmiServiceName) + '@'));
562e5a99777SAlbert Zhang     }
563e5a99777SAlbert Zhang 
5645f4c798dSJiaqing Zhao     if (sshEnabled)
565e5a99777SAlbert Zhang     {
56669320d54SJiaqing Zhao         handleProtocolEnabled(*sshEnabled, asyncResp,
56769320d54SJiaqing Zhao                               encodeServiceObjectPath(sshServiceName));
56867a78d87STom Joseph     }
569e634b34cSEd Tanous }
570e634b34cSEd Tanous 
571af20dd1cSEd Tanous inline void handleManagersNetworkProtocolHead(
572e634b34cSEd Tanous     App& app, const crow::Request& req,
573253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
574253f11b8SEd Tanous     const std::string& managerId)
575e634b34cSEd Tanous {
576e634b34cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
577e634b34cSEd Tanous     {
578e634b34cSEd Tanous         return;
579e634b34cSEd Tanous     }
580af20dd1cSEd Tanous     asyncResp->res.addHeader(
581af20dd1cSEd Tanous         boost::beast::http::field::link,
582af20dd1cSEd 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     }
588af20dd1cSEd Tanous }
589af20dd1cSEd Tanous 
590af20dd1cSEd Tanous inline void handleManagersNetworkProtocolGet(
591af20dd1cSEd Tanous     App& app, const crow::Request& req,
592253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
593253f11b8SEd Tanous     const std::string& managerId)
594af20dd1cSEd Tanous {
595253f11b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
596253f11b8SEd Tanous     {
597253f11b8SEd Tanous         return;
598253f11b8SEd Tanous     }
599253f11b8SEd Tanous     asyncResp->res.addHeader(
600253f11b8SEd Tanous         boost::beast::http::field::link,
601253f11b8SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
602253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
603253f11b8SEd Tanous     {
604253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
605253f11b8SEd Tanous         return;
606253f11b8SEd Tanous     }
607253f11b8SEd Tanous 
608e634b34cSEd Tanous     getNetworkData(asyncResp, req);
609e634b34cSEd Tanous }
610e634b34cSEd Tanous 
611e634b34cSEd Tanous inline void requestRoutesNetworkProtocol(App& app)
612e634b34cSEd Tanous {
613253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
614e634b34cSEd Tanous         .privileges(redfish::privileges::patchManagerNetworkProtocol)
615e634b34cSEd Tanous         .methods(boost::beast::http::verb::patch)(
616e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolPatch, std::ref(app)));
6177e860f15SJohn Edward Broadbent 
618253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
619e9f71672SEd Tanous         .privileges(redfish::privileges::headManagerNetworkProtocol)
620e9f71672SEd Tanous         .methods(boost::beast::http::verb::head)(
621af20dd1cSEd Tanous             std::bind_front(handleManagersNetworkProtocolHead, std::ref(app)));
622e9f71672SEd Tanous 
623253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
624ed398213SEd Tanous         .privileges(redfish::privileges::getManagerNetworkProtocol)
6257e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
626e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolGet, std::ref(app)));
627cf05f9dcSJohnathan Mantey }
62870141561SBorawski.Lukasz 
62970141561SBorawski.Lukasz } // namespace redfish
630