xref: /openbmc/bmcweb/features/redfish/lib/network_protocol.hpp (revision 0eebcefbc0cacc5c4e431ceec80df7fe37b6f56c)
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"
21539d8c6bSEd Tanous #include "generated/enums/resource.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>
29253f11b8SEd 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>
36*0eebcefbSJishnu CM #include <vector>
375f4c798dSJiaqing Zhao 
381abe55efSEd Tanous namespace redfish
391abe55efSEd Tanous {
4070141561SBorawski.Lukasz 
417e860f15SJohn Edward Broadbent void getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp);
427e860f15SJohn Edward Broadbent std::string getHostName();
437e860f15SJohn Edward Broadbent 
445c3e9272SAbhishek Patel static constexpr std::string_view sshServiceName = "dropbear";
455c3e9272SAbhishek Patel static constexpr std::string_view httpsServiceName = "bmcweb";
465c3e9272SAbhishek Patel static constexpr std::string_view ipmiServiceName = "phosphor-ipmi-net";
475c3e9272SAbhishek Patel 
485c3e9272SAbhishek Patel // Mapping from Redfish NetworkProtocol key name to backend service that hosts
495c3e9272SAbhishek Patel // that protocol.
505c3e9272SAbhishek Patel static constexpr std::array<std::pair<std::string_view, std::string_view>, 3>
515c3e9272SAbhishek Patel     networkProtocolToDbus = {{{"SSH", sshServiceName},
5269320d54SJiaqing Zhao                               {"HTTPS", httpsServiceName},
5369320d54SJiaqing Zhao                               {"IPMI", ipmiServiceName}}};
543a8a0088SKowalski, Kamil 
55711ac7a9SEd Tanous inline void extractNTPServersAndDomainNamesData(
56711ac7a9SEd Tanous     const dbus::utility::ManagedObjectType& dbusData,
57*0eebcefbSJishnu CM     std::vector<std::string>& ntpData, std::vector<std::string>& dynamicNtpData,
58*0eebcefbSJishnu CM     std::vector<std::string>& dnData)
5920e6ea5dSraviteja-b {
6081ce609eSEd Tanous     for (const auto& obj : dbusData)
6120e6ea5dSraviteja-b     {
6220e6ea5dSraviteja-b         for (const auto& ifacePair : obj.second)
6320e6ea5dSraviteja-b         {
640a052baaSGeorge Liu             if (ifacePair.first !=
6520e6ea5dSraviteja-b                 "xyz.openbmc_project.Network.EthernetInterface")
6620e6ea5dSraviteja-b             {
670a052baaSGeorge Liu                 continue;
680a052baaSGeorge Liu             }
690a052baaSGeorge Liu 
7020e6ea5dSraviteja-b             for (const auto& propertyPair : ifacePair.second)
7120e6ea5dSraviteja-b             {
72fcd2682aSEd Tanous                 if (propertyPair.first == "StaticNTPServers")
7320e6ea5dSraviteja-b                 {
7420e6ea5dSraviteja-b                     const std::vector<std::string>* ntpServers =
758d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
7620e6ea5dSraviteja-b                             &propertyPair.second);
7720e6ea5dSraviteja-b                     if (ntpServers != nullptr)
7820e6ea5dSraviteja-b                     {
79c251fe81SJian Zhang                         ntpData.insert(ntpData.end(), ntpServers->begin(),
80c251fe81SJian Zhang                                        ntpServers->end());
8120e6ea5dSraviteja-b                     }
8220e6ea5dSraviteja-b                 }
83*0eebcefbSJishnu CM                 else if (propertyPair.first == "NTPServers")
84*0eebcefbSJishnu CM                 {
85*0eebcefbSJishnu CM                     const std::vector<std::string>* dynamicNtpServers =
86*0eebcefbSJishnu CM                         std::get_if<std::vector<std::string>>(
87*0eebcefbSJishnu CM                             &propertyPair.second);
88*0eebcefbSJishnu CM                     if (dynamicNtpServers != nullptr)
89*0eebcefbSJishnu CM                     {
90*0eebcefbSJishnu CM                         dynamicNtpData = *dynamicNtpServers;
91*0eebcefbSJishnu CM                     }
92*0eebcefbSJishnu CM                 }
93d24bfc7aSJennifer Lee                 else if (propertyPair.first == "DomainName")
94d24bfc7aSJennifer Lee                 {
95d24bfc7aSJennifer Lee                     const std::vector<std::string>* domainNames =
968d78b7a9SPatrick Williams                         std::get_if<std::vector<std::string>>(
97d24bfc7aSJennifer Lee                             &propertyPair.second);
98d24bfc7aSJennifer Lee                     if (domainNames != nullptr)
99d24bfc7aSJennifer Lee                     {
100c251fe81SJian Zhang                         dnData.insert(dnData.end(), domainNames->begin(),
101c251fe81SJian Zhang                                       domainNames->end());
102d24bfc7aSJennifer Lee                     }
103d24bfc7aSJennifer Lee                 }
10420e6ea5dSraviteja-b             }
10520e6ea5dSraviteja-b         }
10620e6ea5dSraviteja-b     }
1070225b87bSEd Tanous     stl_utils::removeDuplicate(ntpData);
108c251fe81SJian Zhang     stl_utils::removeDuplicate(dnData);
10920e6ea5dSraviteja-b }
11020e6ea5dSraviteja-b 
11120e6ea5dSraviteja-b template <typename CallbackFunc>
11220e6ea5dSraviteja-b void getEthernetIfaceData(CallbackFunc&& callback)
11320e6ea5dSraviteja-b {
1145eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1155eb468daSGeorge Liu     dbus::utility::getManagedObjects(
1165eb468daSGeorge Liu         "xyz.openbmc_project.Network", path,
1178cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback)](
1188b24275dSEd Tanous             const boost::system::error_code& ec,
119711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& dbusData) {
12020e6ea5dSraviteja-b             std::vector<std::string> ntpServers;
121*0eebcefbSJishnu CM             std::vector<std::string> dynamicNtpServers;
122d24bfc7aSJennifer Lee             std::vector<std::string> domainNames;
12320e6ea5dSraviteja-b 
1248b24275dSEd Tanous             if (ec)
12520e6ea5dSraviteja-b             {
126*0eebcefbSJishnu CM                 callback(false, ntpServers, dynamicNtpServers, domainNames);
12720e6ea5dSraviteja-b                 return;
12820e6ea5dSraviteja-b             }
12920e6ea5dSraviteja-b 
130bd79bce8SPatrick Williams             extractNTPServersAndDomainNamesData(dbusData, ntpServers,
131*0eebcefbSJishnu CM                                                 dynamicNtpServers, domainNames);
13220e6ea5dSraviteja-b 
133*0eebcefbSJishnu CM             callback(true, ntpServers, dynamicNtpServers, domainNames);
1345eb468daSGeorge Liu         });
135271584abSEd Tanous }
13620e6ea5dSraviteja-b 
1375c3e9272SAbhishek Patel inline void afterNetworkPortRequest(
1385c3e9272SAbhishek Patel     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1395c3e9272SAbhishek Patel     const boost::system::error_code& ec,
1405c3e9272SAbhishek Patel     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
1415c3e9272SAbhishek Patel {
1425c3e9272SAbhishek Patel     if (ec)
1435c3e9272SAbhishek Patel     {
1445c3e9272SAbhishek Patel         messages::internalError(asyncResp->res);
1455c3e9272SAbhishek Patel         return;
1465c3e9272SAbhishek Patel     }
1475c3e9272SAbhishek Patel     for (const auto& data : socketData)
1485c3e9272SAbhishek Patel     {
1495c3e9272SAbhishek Patel         const std::string& socketPath = get<0>(data);
1505c3e9272SAbhishek Patel         const std::string& protocolName = get<1>(data);
1515c3e9272SAbhishek Patel         bool isProtocolEnabled = get<2>(data);
1525c3e9272SAbhishek Patel 
1535c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["ProtocolEnabled"] =
1545c3e9272SAbhishek Patel             isProtocolEnabled;
1555c3e9272SAbhishek Patel         asyncResp->res.jsonValue[protocolName]["Port"] = nullptr;
1565c3e9272SAbhishek Patel         getPortNumber(socketPath, [asyncResp, protocolName](
1575c3e9272SAbhishek Patel                                       const boost::system::error_code& ec2,
1585c3e9272SAbhishek Patel                                       int portNumber) {
1595c3e9272SAbhishek Patel             if (ec2)
1605c3e9272SAbhishek Patel             {
1615c3e9272SAbhishek Patel                 messages::internalError(asyncResp->res);
1625c3e9272SAbhishek Patel                 return;
1635c3e9272SAbhishek Patel             }
1645c3e9272SAbhishek Patel             asyncResp->res.jsonValue[protocolName]["Port"] = portNumber;
1655c3e9272SAbhishek Patel         });
1665c3e9272SAbhishek Patel     }
1675c3e9272SAbhishek Patel }
1685c3e9272SAbhishek Patel 
1694f48d5f6SEd Tanous inline void getNetworkData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
17072048780SAbhishek Patel                            const crow::Request& req)
1711abe55efSEd Tanous {
1723e72c202SNinad Palsule     if (req.session == nullptr)
1733e72c202SNinad Palsule     {
1743e72c202SNinad Palsule         messages::internalError(asyncResp->res);
1753e72c202SNinad Palsule         return;
1763e72c202SNinad Palsule     }
1773e72c202SNinad Palsule 
178e9f71672SEd Tanous     asyncResp->res.addHeader(
179e9f71672SEd Tanous         boost::beast::http::field::link,
180e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/NetworkProtocol.json>; rel=describedby");
1810f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
182*0eebcefbSJishnu CM         "#ManagerNetworkProtocol.v1_9_0.ManagerNetworkProtocol";
1830f74e643SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
184253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol",
185253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
1860f74e643SEd Tanous     asyncResp->res.jsonValue["Id"] = "NetworkProtocol";
1870f74e643SEd Tanous     asyncResp->res.jsonValue["Name"] = "Manager Network Protocol";
1880f74e643SEd Tanous     asyncResp->res.jsonValue["Description"] = "Manager Network Service";
189539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
190539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["HealthRollup"] = resource::Health::OK;
191539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
1920f74e643SEd Tanous 
19361932318SXiaochao Ma     // HTTP is Mandatory attribute as per OCP Baseline Profile - v1.0.0,
194818ea7b8SJoshi-Mansi     // but from security perspective it is not recommended to use.
195818ea7b8SJoshi-Mansi     // Hence using protocolEnabled as false to make it OCP and security-wise
196818ea7b8SJoshi-Mansi     // compliant
1975c3e9272SAbhishek Patel     asyncResp->res.jsonValue["HTTP"]["Port"] = nullptr;
198818ea7b8SJoshi-Mansi     asyncResp->res.jsonValue["HTTP"]["ProtocolEnabled"] = false;
199818ea7b8SJoshi-Mansi 
2001ee2db7fSAndrew Geissler     // The ProtocolEnabled of the following protocols is determined by
2011ee2db7fSAndrew Geissler     // inspecting the state of associated systemd sockets. If these protocols
2021ee2db7fSAndrew Geissler     // have been disabled, then the systemd socket unit files will not be found
2031ee2db7fSAndrew Geissler     // and the protocols will not be returned in this Redfish query. Set some
2041ee2db7fSAndrew Geissler     // defaults to ensure something is always returned.
2051ee2db7fSAndrew Geissler     for (const auto& nwkProtocol : networkProtocolToDbus)
2061ee2db7fSAndrew Geissler     {
2071ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["Port"] = nullptr;
2081ee2db7fSAndrew Geissler         asyncResp->res.jsonValue[nwkProtocol.first]["ProtocolEnabled"] = false;
2091ee2db7fSAndrew Geissler     }
2101ee2db7fSAndrew Geissler 
211d24bfc7aSJennifer Lee     std::string hostName = getHostName();
212d24bfc7aSJennifer Lee 
213d24bfc7aSJennifer Lee     asyncResp->res.jsonValue["HostName"] = hostName;
2143a8a0088SKowalski, Kamil 
21520e6ea5dSraviteja-b     getNTPProtocolEnabled(asyncResp);
21620e6ea5dSraviteja-b 
217bd79bce8SPatrick Williams     getEthernetIfaceData([hostName, asyncResp](
218bd79bce8SPatrick Williams                              const bool& success,
21902cad96eSEd Tanous                              const std::vector<std::string>& ntpServers,
220*0eebcefbSJishnu CM                              const std::vector<std::string>& dynamicNtpServers,
221d24bfc7aSJennifer Lee                              const std::vector<std::string>& domainNames) {
22220e6ea5dSraviteja-b         if (!success)
22320e6ea5dSraviteja-b         {
2240a052baaSGeorge Liu             messages::resourceNotFound(asyncResp->res, "ManagerNetworkProtocol",
2250a052baaSGeorge Liu                                        "NetworkProtocol");
22620e6ea5dSraviteja-b             return;
22720e6ea5dSraviteja-b         }
22820e6ea5dSraviteja-b         asyncResp->res.jsonValue["NTP"]["NTPServers"] = ntpServers;
229*0eebcefbSJishnu CM         asyncResp->res.jsonValue["NTP"]["NetworkSuppliedServers"] =
230*0eebcefbSJishnu CM             dynamicNtpServers;
23126f6976fSEd Tanous         if (!hostName.empty())
232d24bfc7aSJennifer Lee         {
233f23b7296SEd Tanous             std::string fqdn = hostName;
23426f6976fSEd Tanous             if (!domainNames.empty())
235d24bfc7aSJennifer Lee             {
236f23b7296SEd Tanous                 fqdn += ".";
237f23b7296SEd Tanous                 fqdn += domainNames[0];
238d24bfc7aSJennifer Lee             }
2392c70f800SEd Tanous             asyncResp->res.jsonValue["FQDN"] = std::move(fqdn);
240d24bfc7aSJennifer Lee         }
24120e6ea5dSraviteja-b     });
24220e6ea5dSraviteja-b 
24372048780SAbhishek Patel     Privileges effectiveUserPrivileges =
2443e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
24572048780SAbhishek Patel 
24672048780SAbhishek Patel     // /redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates is
24772048780SAbhishek Patel     // something only ConfigureManager can access then only display when
24872048780SAbhishek Patel     // the user has permissions ConfigureManager
24972048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
25072048780SAbhishek Patel                                          effectiveUserPrivileges))
25172048780SAbhishek Patel     {
2521476687dSEd Tanous         asyncResp->res.jsonValue["HTTPS"]["Certificates"]["@odata.id"] =
253253f11b8SEd Tanous             boost::urls::format(
254253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
255253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME);
25670141561SBorawski.Lukasz     }
25770141561SBorawski.Lukasz 
2585c3e9272SAbhishek Patel     getPortStatusAndPath(std::span(networkProtocolToDbus),
2595c3e9272SAbhishek Patel                          std::bind_front(afterNetworkPortRequest, asyncResp));
260b4bec66bSAbhishek Patel } // namespace redfish
261501be32bSraviteja-b 
2628e157735SEd Tanous inline void afterSetNTP(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2638e157735SEd Tanous                         const boost::system::error_code& ec)
26420e6ea5dSraviteja-b {
2658e157735SEd Tanous     if (ec)
26620e6ea5dSraviteja-b     {
2678e157735SEd Tanous         BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}",
2688e157735SEd Tanous                          ec);
2698e157735SEd Tanous         messages::internalError(asyncResp->res);
2708e157735SEd Tanous         return;
27120e6ea5dSraviteja-b     }
2728e157735SEd Tanous     asyncResp->res.result(boost::beast::http::status::no_content);
27320e6ea5dSraviteja-b }
27420e6ea5dSraviteja-b 
2758e157735SEd Tanous inline void handleNTPProtocolEnabled(
2768e157735SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, bool ntpEnabled)
2778e157735SEd Tanous {
2788e157735SEd Tanous     bool interactive = false;
2798e157735SEd Tanous     auto callback = [asyncResp](const boost::system::error_code& ec) {
2808e157735SEd Tanous         afterSetNTP(asyncResp, ec);
2818e157735SEd Tanous     };
2828e157735SEd Tanous     crow::connections::systemBus->async_method_call(
2838e157735SEd Tanous         std::move(callback), "org.freedesktop.timedate1",
2848e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "SetNTP",
2858e157735SEd Tanous         ntpEnabled, interactive);
28620e6ea5dSraviteja-b }
28720e6ea5dSraviteja-b 
288ed4de7a8SEd Tanous // Redfish states that ip addresses can be
289ed4de7a8SEd Tanous // string, to set a value
290ed4de7a8SEd Tanous // null, to delete the value
291ed4de7a8SEd Tanous // object_t, empty json object, to ignore the value
292ed4de7a8SEd Tanous using IpAddress =
293ed4de7a8SEd Tanous     std::variant<std::string, nlohmann::json::object_t, std::nullptr_t>;
294ed4de7a8SEd Tanous 
2954f48d5f6SEd Tanous inline void
296287ece64SGeorge Liu     handleNTPServersPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
297ed4de7a8SEd Tanous                           const std::vector<IpAddress>& ntpServerObjects,
298b9e15228SEd Tanous                           std::vector<std::string> currentNtpServers)
29920e6ea5dSraviteja-b {
300b9e15228SEd Tanous     std::vector<std::string>::iterator currentNtpServer =
301b9e15228SEd Tanous         currentNtpServers.begin();
302b9e15228SEd Tanous     for (size_t index = 0; index < ntpServerObjects.size(); index++)
303287ece64SGeorge Liu     {
304ed4de7a8SEd Tanous         const IpAddress& ntpServer = ntpServerObjects[index];
305ed4de7a8SEd Tanous         if (std::holds_alternative<std::nullptr_t>(ntpServer))
306b9e15228SEd Tanous         {
307b9e15228SEd Tanous             // Can't delete an item that doesn't exist
308b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
309b9e15228SEd Tanous             {
310bd79bce8SPatrick Williams                 messages::propertyValueNotInList(
311bd79bce8SPatrick Williams                     asyncResp->res, "null",
312bd79bce8SPatrick Williams                     "NTP/NTPServers/" + std::to_string(index));
313b9e15228SEd Tanous 
314287ece64SGeorge Liu                 return;
315287ece64SGeorge Liu             }
316b9e15228SEd Tanous             currentNtpServer = currentNtpServers.erase(currentNtpServer);
317b9e15228SEd Tanous             continue;
318b9e15228SEd Tanous         }
319b9e15228SEd Tanous         const nlohmann::json::object_t* ntpServerObject =
320ed4de7a8SEd Tanous             std::get_if<nlohmann::json::object_t>(&ntpServer);
321b9e15228SEd Tanous         if (ntpServerObject != nullptr)
322b9e15228SEd Tanous         {
323b9e15228SEd Tanous             if (!ntpServerObject->empty())
324b9e15228SEd Tanous             {
325ed4de7a8SEd Tanous                 messages::propertyValueNotInList(
326ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
327ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
328b9e15228SEd Tanous                 return;
329b9e15228SEd Tanous             }
330b9e15228SEd Tanous             // Can't retain an item that doesn't exist
331b9e15228SEd Tanous             if (currentNtpServer == currentNtpServers.end())
332b9e15228SEd Tanous             {
333ed4de7a8SEd Tanous                 messages::propertyValueOutOfRange(
334ed4de7a8SEd Tanous                     asyncResp->res, *ntpServerObject,
335ed4de7a8SEd Tanous                     "NTP/NTPServers/" + std::to_string(index));
336b9e15228SEd Tanous 
337b9e15228SEd Tanous                 return;
338b9e15228SEd Tanous             }
339b9e15228SEd Tanous             // empty objects should leave the NtpServer unmodified
340b9e15228SEd Tanous             currentNtpServer++;
341b9e15228SEd Tanous             continue;
342b9e15228SEd Tanous         }
343b9e15228SEd Tanous 
344ed4de7a8SEd Tanous         const std::string* ntpServerStr = std::get_if<std::string>(&ntpServer);
345b9e15228SEd Tanous         if (ntpServerStr == nullptr)
346b9e15228SEd Tanous         {
347ed4de7a8SEd Tanous             messages::internalError(asyncResp->res);
348b9e15228SEd Tanous             return;
349b9e15228SEd Tanous         }
350b9e15228SEd Tanous         if (currentNtpServer == currentNtpServers.end())
351b9e15228SEd Tanous         {
352b9e15228SEd Tanous             // if we're at the end of the list, append to the end
353b9e15228SEd Tanous             currentNtpServers.push_back(*ntpServerStr);
354b9e15228SEd Tanous             currentNtpServer = currentNtpServers.end();
355b9e15228SEd Tanous             continue;
356b9e15228SEd Tanous         }
357b9e15228SEd Tanous         *currentNtpServer = *ntpServerStr;
358b9e15228SEd Tanous         currentNtpServer++;
359b9e15228SEd Tanous     }
360b9e15228SEd Tanous 
361b9e15228SEd Tanous     // Any remaining array elements should be removed
362b9e15228SEd Tanous     currentNtpServers.erase(currentNtpServer, currentNtpServers.end());
363287ece64SGeorge Liu 
364e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> ethInterfaces = {
365e99073f5SGeorge Liu         "xyz.openbmc_project.Network.EthernetInterface"};
366e99073f5SGeorge Liu     dbus::utility::getSubTree(
367e99073f5SGeorge Liu         "/xyz/openbmc_project", 0, ethInterfaces,
368b9e15228SEd Tanous         [asyncResp, currentNtpServers](
3692138483cSGeorge Liu             const boost::system::error_code& ec,
370b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& subtree) {
3710a052baaSGeorge Liu             if (ec)
3720a052baaSGeorge Liu             {
37362598e31SEd Tanous                 BMCWEB_LOG_WARNING("D-Bus error: {}, {}", ec, ec.message());
3740a052baaSGeorge Liu                 messages::internalError(asyncResp->res);
3750a052baaSGeorge Liu                 return;
3760a052baaSGeorge Liu             }
3770a052baaSGeorge Liu 
3780a052baaSGeorge Liu             for (const auto& [objectPath, serviceMap] : subtree)
3790a052baaSGeorge Liu             {
3800a052baaSGeorge Liu                 for (const auto& [service, interfaces] : serviceMap)
3810a052baaSGeorge Liu                 {
3820a052baaSGeorge Liu                     for (const auto& interface : interfaces)
3830a052baaSGeorge Liu                     {
3840a052baaSGeorge Liu                         if (interface !=
3850a052baaSGeorge Liu                             "xyz.openbmc_project.Network.EthernetInterface")
3860a052baaSGeorge Liu                         {
3870a052baaSGeorge Liu                             continue;
3880a052baaSGeorge Liu                         }
3890a052baaSGeorge Liu 
390e93abac6SGinu George                         setDbusProperty(asyncResp, "NTP/NTPServers/", service,
391bd79bce8SPatrick Williams                                         objectPath, interface,
392bd79bce8SPatrick Williams                                         "StaticNTPServers", currentNtpServers);
39320e6ea5dSraviteja-b                     }
3940a052baaSGeorge Liu                 }
3950a052baaSGeorge Liu             }
396e99073f5SGeorge Liu         });
3970a052baaSGeorge Liu }
39820e6ea5dSraviteja-b 
3994f48d5f6SEd Tanous inline void
4004f48d5f6SEd Tanous     handleProtocolEnabled(const bool protocolEnabled,
401e5a99777SAlbert Zhang                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40269320d54SJiaqing Zhao                           const std::string& netBasePath)
40367a78d87STom Joseph {
404e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
405e99073f5SGeorge Liu         "xyz.openbmc_project.Control.Service.Attributes"};
406e99073f5SGeorge Liu     dbus::utility::getSubTree(
407e99073f5SGeorge Liu         "/xyz/openbmc_project/control/service", 0, interfaces,
408e5a99777SAlbert Zhang         [protocolEnabled, asyncResp,
4092138483cSGeorge Liu          netBasePath](const boost::system::error_code& ec,
410b9d36b47SEd Tanous                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
41167a78d87STom Joseph             if (ec)
41267a78d87STom Joseph             {
41367a78d87STom Joseph                 messages::internalError(asyncResp->res);
41467a78d87STom Joseph                 return;
41567a78d87STom Joseph             }
41667a78d87STom Joseph 
41767a78d87STom Joseph             for (const auto& entry : subtree)
41867a78d87STom Joseph             {
41918f8f608SEd Tanous                 if (entry.first.starts_with(netBasePath))
42067a78d87STom Joseph                 {
42187c44966SAsmitha Karunanithi                     setDbusProperty(
422e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
423e93abac6SGinu George                         entry.second.begin()->first, entry.first,
424bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
425bd79bce8SPatrick Williams                         "Running", protocolEnabled);
42687c44966SAsmitha Karunanithi                     setDbusProperty(
427e93abac6SGinu George                         asyncResp, "IPMI/ProtocolEnabled",
428e93abac6SGinu George                         entry.second.begin()->first, entry.first,
429bd79bce8SPatrick Williams                         "xyz.openbmc_project.Control.Service.Attributes",
430bd79bce8SPatrick Williams                         "Enabled", protocolEnabled);
43167a78d87STom Joseph                 }
43267a78d87STom Joseph             }
433e99073f5SGeorge Liu         });
43467a78d87STom Joseph }
43567a78d87STom Joseph 
4364f48d5f6SEd Tanous inline std::string getHostName()
437501be32bSraviteja-b {
4387e860f15SJohn Edward Broadbent     std::string hostName;
4398d1b46d7Szhanghch05 
440d3a9e084SEd Tanous     std::array<char, HOST_NAME_MAX> hostNameCStr{};
4417e860f15SJohn Edward Broadbent     if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0)
4427e860f15SJohn Edward Broadbent     {
4437e860f15SJohn Edward Broadbent         hostName = hostNameCStr.data();
4447e860f15SJohn Edward Broadbent     }
4457e860f15SJohn Edward Broadbent     return hostName;
4467e860f15SJohn Edward Broadbent }
4477e860f15SJohn Edward Broadbent 
4484f48d5f6SEd Tanous inline void
4494f48d5f6SEd Tanous     getNTPProtocolEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4507e860f15SJohn Edward Broadbent {
4518e157735SEd Tanous     sdbusplus::asio::getProperty<bool>(
4528e157735SEd Tanous         *crow::connections::systemBus, "org.freedesktop.timedate1",
4538e157735SEd Tanous         "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP",
4548e157735SEd Tanous         [asyncResp](const boost::system::error_code& ec, bool enabled) {
4558b24275dSEd Tanous             if (ec)
4567e860f15SJohn Edward Broadbent             {
4578e157735SEd Tanous                 BMCWEB_LOG_WARNING(
4588e157735SEd Tanous                     "Failed to get NTP status, assuming not supported");
4597e860f15SJohn Edward Broadbent                 return;
4607e860f15SJohn Edward Broadbent             }
4617e860f15SJohn Edward Broadbent 
4628e157735SEd Tanous             asyncResp->res.jsonValue["NTP"]["ProtocolEnabled"] = enabled;
4631e1e598dSJonathan Doman         });
4647e860f15SJohn Edward Broadbent }
4657e860f15SJohn Edward Broadbent 
4665c3e9272SAbhishek Patel inline std::string encodeServiceObjectPath(std::string_view serviceName)
46769320d54SJiaqing Zhao {
46869320d54SJiaqing Zhao     sdbusplus::message::object_path objPath(
46969320d54SJiaqing Zhao         "/xyz/openbmc_project/control/service");
47069320d54SJiaqing Zhao     objPath /= serviceName;
47169320d54SJiaqing Zhao     return objPath.str;
47269320d54SJiaqing Zhao }
47369320d54SJiaqing Zhao 
4740f55d946SEd Tanous inline void handleBmcNetworkProtocolHead(
475e9f71672SEd Tanous     crow::App& app, const crow::Request& req,
476e9f71672SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
477e9f71672SEd Tanous {
478e9f71672SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
479e9f71672SEd Tanous     {
480e9f71672SEd Tanous         return;
481e9f71672SEd Tanous     }
482e9f71672SEd Tanous     asyncResp->res.addHeader(
483e9f71672SEd Tanous         boost::beast::http::field::link,
484e9f71672SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
485e9f71672SEd Tanous }
486e9f71672SEd Tanous 
487e634b34cSEd Tanous inline void handleManagersNetworkProtocolPatch(
488e634b34cSEd Tanous     App& app, const crow::Request& req,
489253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
490253f11b8SEd Tanous     const std::string& managerId)
4917e860f15SJohn Edward Broadbent {
4923ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
49345ca1b86SEd Tanous     {
49445ca1b86SEd Tanous         return;
49545ca1b86SEd Tanous     }
496253f11b8SEd Tanous 
497253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
498253f11b8SEd Tanous     {
499253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
500253f11b8SEd Tanous         return;
501253f11b8SEd Tanous     }
502253f11b8SEd Tanous 
503501be32bSraviteja-b     std::optional<std::string> newHostName;
504ed4de7a8SEd Tanous 
505ed4de7a8SEd Tanous     std::optional<std::vector<IpAddress>> ntpServerObjects;
5065f4c798dSJiaqing Zhao     std::optional<bool> ntpEnabled;
5075f4c798dSJiaqing Zhao     std::optional<bool> ipmiEnabled;
5085f4c798dSJiaqing Zhao     std::optional<bool> sshEnabled;
509501be32bSraviteja-b 
5105f4c798dSJiaqing Zhao     // clang-format off
5115f4c798dSJiaqing Zhao         if (!json_util::readJsonPatch(
5125f4c798dSJiaqing Zhao                 req, asyncResp->res,
5135f4c798dSJiaqing Zhao                 "HostName", newHostName,
514b9e15228SEd Tanous                 "NTP/NTPServers", ntpServerObjects,
5155f4c798dSJiaqing Zhao                 "NTP/ProtocolEnabled", ntpEnabled,
5165f4c798dSJiaqing Zhao                 "IPMI/ProtocolEnabled", ipmiEnabled,
5175f4c798dSJiaqing Zhao                 "SSH/ProtocolEnabled", sshEnabled))
518501be32bSraviteja-b         {
519501be32bSraviteja-b             return;
520501be32bSraviteja-b         }
5215f4c798dSJiaqing Zhao     // clang-format on
522cf05f9dcSJohnathan Mantey 
5238d1b46d7Szhanghch05     asyncResp->res.result(boost::beast::http::status::no_content);
524501be32bSraviteja-b     if (newHostName)
525501be32bSraviteja-b     {
5262db77d34SJohnathan Mantey         messages::propertyNotWritable(asyncResp->res, "HostName");
52744fad2aaSEd Tanous         return;
528cf05f9dcSJohnathan Mantey     }
529cf05f9dcSJohnathan Mantey 
53020e6ea5dSraviteja-b     if (ntpEnabled)
53120e6ea5dSraviteja-b     {
5328e157735SEd Tanous         handleNTPProtocolEnabled(asyncResp, *ntpEnabled);
53320e6ea5dSraviteja-b     }
534b9e15228SEd Tanous     if (ntpServerObjects)
53520e6ea5dSraviteja-b     {
536b9e15228SEd Tanous         getEthernetIfaceData(
537b9e15228SEd Tanous             [asyncResp, ntpServerObjects](
538e634b34cSEd Tanous                 const bool success, std::vector<std::string>& currentNtpServers,
539*0eebcefbSJishnu CM                 const std::vector<std::string>& /*dynamicNtpServers*/,
540b9e15228SEd Tanous                 const std::vector<std::string>& /*domainNames*/) {
541b9e15228SEd Tanous                 if (!success)
542b9e15228SEd Tanous                 {
543b9e15228SEd Tanous                     messages::internalError(asyncResp->res);
544b9e15228SEd Tanous                     return;
545b9e15228SEd Tanous                 }
546b9e15228SEd Tanous                 handleNTPServersPatch(asyncResp, *ntpServerObjects,
547b9e15228SEd Tanous                                       std::move(currentNtpServers));
548b9e15228SEd Tanous             });
54920e6ea5dSraviteja-b     }
55067a78d87STom Joseph 
5515f4c798dSJiaqing Zhao     if (ipmiEnabled)
55267a78d87STom Joseph     {
553e5a99777SAlbert Zhang         handleProtocolEnabled(
5545f4c798dSJiaqing Zhao             *ipmiEnabled, asyncResp,
55569320d54SJiaqing Zhao             encodeServiceObjectPath(std::string(ipmiServiceName) + '@'));
556e5a99777SAlbert Zhang     }
557e5a99777SAlbert Zhang 
5585f4c798dSJiaqing Zhao     if (sshEnabled)
559e5a99777SAlbert Zhang     {
56069320d54SJiaqing Zhao         handleProtocolEnabled(*sshEnabled, asyncResp,
56169320d54SJiaqing Zhao                               encodeServiceObjectPath(sshServiceName));
56267a78d87STom Joseph     }
563e634b34cSEd Tanous }
564e634b34cSEd Tanous 
565af20dd1cSEd Tanous inline void handleManagersNetworkProtocolHead(
566e634b34cSEd Tanous     App& app, const crow::Request& req,
567253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
568253f11b8SEd Tanous     const std::string& managerId)
569e634b34cSEd Tanous {
570e634b34cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
571e634b34cSEd Tanous     {
572e634b34cSEd Tanous         return;
573e634b34cSEd Tanous     }
574af20dd1cSEd Tanous     asyncResp->res.addHeader(
575af20dd1cSEd Tanous         boost::beast::http::field::link,
576af20dd1cSEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
577253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
578253f11b8SEd Tanous     {
579253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
580253f11b8SEd Tanous         return;
581253f11b8SEd Tanous     }
582af20dd1cSEd Tanous }
583af20dd1cSEd Tanous 
584af20dd1cSEd Tanous inline void handleManagersNetworkProtocolGet(
585af20dd1cSEd Tanous     App& app, const crow::Request& req,
586253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
587253f11b8SEd Tanous     const std::string& managerId)
588af20dd1cSEd Tanous {
589253f11b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
590253f11b8SEd Tanous     {
591253f11b8SEd Tanous         return;
592253f11b8SEd Tanous     }
593253f11b8SEd Tanous     asyncResp->res.addHeader(
594253f11b8SEd Tanous         boost::beast::http::field::link,
595253f11b8SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
596253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
597253f11b8SEd Tanous     {
598253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
599253f11b8SEd Tanous         return;
600253f11b8SEd Tanous     }
601253f11b8SEd Tanous 
602e634b34cSEd Tanous     getNetworkData(asyncResp, req);
603e634b34cSEd Tanous }
604e634b34cSEd Tanous 
605e634b34cSEd Tanous inline void requestRoutesNetworkProtocol(App& app)
606e634b34cSEd Tanous {
607253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
608e634b34cSEd Tanous         .privileges(redfish::privileges::patchManagerNetworkProtocol)
609e634b34cSEd Tanous         .methods(boost::beast::http::verb::patch)(
610e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolPatch, std::ref(app)));
6117e860f15SJohn Edward Broadbent 
612253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
613e9f71672SEd Tanous         .privileges(redfish::privileges::headManagerNetworkProtocol)
614e9f71672SEd Tanous         .methods(boost::beast::http::verb::head)(
615af20dd1cSEd Tanous             std::bind_front(handleManagersNetworkProtocolHead, std::ref(app)));
616e9f71672SEd Tanous 
617253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
618ed398213SEd Tanous         .privileges(redfish::privileges::getManagerNetworkProtocol)
6197e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
620e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolGet, std::ref(app)));
621cf05f9dcSJohnathan Mantey }
62270141561SBorawski.Lukasz 
62370141561SBorawski.Lukasz } // namespace redfish
624