xref: /openbmc/bmcweb/features/redfish/lib/network_protocol.hpp (revision deae6a789444debc4724fb6902fc5def299afbee)
170141561SBorawski.Lukasz /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous 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>
360eebcefbSJishnu 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,
570eebcefbSJishnu CM     std::vector<std::string>& ntpData, std::vector<std::string>& dynamicNtpData,
580eebcefbSJishnu 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                 }
830eebcefbSJishnu CM                 else if (propertyPair.first == "NTPServers")
840eebcefbSJishnu CM                 {
850eebcefbSJishnu CM                     const std::vector<std::string>* dynamicNtpServers =
860eebcefbSJishnu CM                         std::get_if<std::vector<std::string>>(
870eebcefbSJishnu CM                             &propertyPair.second);
880eebcefbSJishnu CM                     if (dynamicNtpServers != nullptr)
890eebcefbSJishnu CM                     {
900eebcefbSJishnu CM                         dynamicNtpData = *dynamicNtpServers;
910eebcefbSJishnu CM                     }
920eebcefbSJishnu 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;
1210eebcefbSJishnu CM             std::vector<std::string> dynamicNtpServers;
122d24bfc7aSJennifer Lee             std::vector<std::string> domainNames;
12320e6ea5dSraviteja-b 
1248b24275dSEd Tanous             if (ec)
12520e6ea5dSraviteja-b             {
1260eebcefbSJishnu CM                 callback(false, ntpServers, dynamicNtpServers, domainNames);
12720e6ea5dSraviteja-b                 return;
12820e6ea5dSraviteja-b             }
12920e6ea5dSraviteja-b 
130bd79bce8SPatrick Williams             extractNTPServersAndDomainNamesData(dbusData, ntpServers,
1310eebcefbSJishnu CM                                                 dynamicNtpServers, domainNames);
13220e6ea5dSraviteja-b 
1330eebcefbSJishnu 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"] =
1820eebcefbSJishnu 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,
2200eebcefbSJishnu 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;
2290eebcefbSJishnu CM         asyncResp->res.jsonValue["NTP"]["NetworkSuppliedServers"] =
2300eebcefbSJishnu 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 {
451*deae6a78SEd Tanous     dbus::utility::getProperty<bool>(
452*deae6a78SEd Tanous         "org.freedesktop.timedate1", "/org/freedesktop/timedate1",
453*deae6a78SEd Tanous         "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     if (!json_util::readJsonPatch(
511afc474aeSMyung Bae             req, asyncResp->res, //
512afc474aeSMyung Bae             "HostName", newHostName, //
513afc474aeSMyung Bae             "NTP/NTPServers", ntpServerObjects, //
514afc474aeSMyung Bae             "NTP/ProtocolEnabled", ntpEnabled, //
515afc474aeSMyung Bae             "IPMI/ProtocolEnabled", ipmiEnabled, //
516afc474aeSMyung Bae             "SSH/ProtocolEnabled", sshEnabled //
517afc474aeSMyung Bae             ))
518501be32bSraviteja-b     {
519501be32bSraviteja-b         return;
520501be32bSraviteja-b     }
521cf05f9dcSJohnathan Mantey 
5228d1b46d7Szhanghch05     asyncResp->res.result(boost::beast::http::status::no_content);
523501be32bSraviteja-b     if (newHostName)
524501be32bSraviteja-b     {
5252db77d34SJohnathan Mantey         messages::propertyNotWritable(asyncResp->res, "HostName");
52644fad2aaSEd Tanous         return;
527cf05f9dcSJohnathan Mantey     }
528cf05f9dcSJohnathan Mantey 
52920e6ea5dSraviteja-b     if (ntpEnabled)
53020e6ea5dSraviteja-b     {
5318e157735SEd Tanous         handleNTPProtocolEnabled(asyncResp, *ntpEnabled);
53220e6ea5dSraviteja-b     }
533b9e15228SEd Tanous     if (ntpServerObjects)
53420e6ea5dSraviteja-b     {
535b9e15228SEd Tanous         getEthernetIfaceData(
536b9e15228SEd Tanous             [asyncResp, ntpServerObjects](
537e634b34cSEd Tanous                 const bool success, std::vector<std::string>& currentNtpServers,
5380eebcefbSJishnu CM                 const std::vector<std::string>& /*dynamicNtpServers*/,
539b9e15228SEd Tanous                 const std::vector<std::string>& /*domainNames*/) {
540b9e15228SEd Tanous                 if (!success)
541b9e15228SEd Tanous                 {
542b9e15228SEd Tanous                     messages::internalError(asyncResp->res);
543b9e15228SEd Tanous                     return;
544b9e15228SEd Tanous                 }
545b9e15228SEd Tanous                 handleNTPServersPatch(asyncResp, *ntpServerObjects,
546b9e15228SEd Tanous                                       std::move(currentNtpServers));
547b9e15228SEd Tanous             });
54820e6ea5dSraviteja-b     }
54967a78d87STom Joseph 
5505f4c798dSJiaqing Zhao     if (ipmiEnabled)
55167a78d87STom Joseph     {
552e5a99777SAlbert Zhang         handleProtocolEnabled(
5535f4c798dSJiaqing Zhao             *ipmiEnabled, asyncResp,
55469320d54SJiaqing Zhao             encodeServiceObjectPath(std::string(ipmiServiceName) + '@'));
555e5a99777SAlbert Zhang     }
556e5a99777SAlbert Zhang 
5575f4c798dSJiaqing Zhao     if (sshEnabled)
558e5a99777SAlbert Zhang     {
55969320d54SJiaqing Zhao         handleProtocolEnabled(*sshEnabled, asyncResp,
56069320d54SJiaqing Zhao                               encodeServiceObjectPath(sshServiceName));
56167a78d87STom Joseph     }
562e634b34cSEd Tanous }
563e634b34cSEd Tanous 
564af20dd1cSEd Tanous inline void handleManagersNetworkProtocolHead(
565e634b34cSEd Tanous     App& app, const crow::Request& req,
566253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
567253f11b8SEd Tanous     const std::string& managerId)
568e634b34cSEd Tanous {
569e634b34cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
570e634b34cSEd Tanous     {
571e634b34cSEd Tanous         return;
572e634b34cSEd Tanous     }
573af20dd1cSEd Tanous     asyncResp->res.addHeader(
574af20dd1cSEd Tanous         boost::beast::http::field::link,
575af20dd1cSEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
576253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
577253f11b8SEd Tanous     {
578253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
579253f11b8SEd Tanous         return;
580253f11b8SEd Tanous     }
581af20dd1cSEd Tanous }
582af20dd1cSEd Tanous 
583af20dd1cSEd Tanous inline void handleManagersNetworkProtocolGet(
584af20dd1cSEd Tanous     App& app, const crow::Request& req,
585253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
586253f11b8SEd Tanous     const std::string& managerId)
587af20dd1cSEd Tanous {
588253f11b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
589253f11b8SEd Tanous     {
590253f11b8SEd Tanous         return;
591253f11b8SEd Tanous     }
592253f11b8SEd Tanous     asyncResp->res.addHeader(
593253f11b8SEd Tanous         boost::beast::http::field::link,
594253f11b8SEd Tanous         "</redfish/v1/JsonSchemas/ManagerNetworkProtocol/ManagerNetworkProtocol.json>; rel=describedby");
595253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
596253f11b8SEd Tanous     {
597253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
598253f11b8SEd Tanous         return;
599253f11b8SEd Tanous     }
600253f11b8SEd Tanous 
601e634b34cSEd Tanous     getNetworkData(asyncResp, req);
602e634b34cSEd Tanous }
603e634b34cSEd Tanous 
604e634b34cSEd Tanous inline void requestRoutesNetworkProtocol(App& app)
605e634b34cSEd Tanous {
606253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
607e634b34cSEd Tanous         .privileges(redfish::privileges::patchManagerNetworkProtocol)
608e634b34cSEd Tanous         .methods(boost::beast::http::verb::patch)(
609e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolPatch, std::ref(app)));
6107e860f15SJohn Edward Broadbent 
611253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
612e9f71672SEd Tanous         .privileges(redfish::privileges::headManagerNetworkProtocol)
613e9f71672SEd Tanous         .methods(boost::beast::http::verb::head)(
614af20dd1cSEd Tanous             std::bind_front(handleManagersNetworkProtocolHead, std::ref(app)));
615e9f71672SEd Tanous 
616253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/NetworkProtocol/")
617ed398213SEd Tanous         .privileges(redfish::privileges::getManagerNetworkProtocol)
6187e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
619e634b34cSEd Tanous             std::bind_front(handleManagersNetworkProtocolGet, std::ref(app)));
620cf05f9dcSJohnathan Mantey }
62170141561SBorawski.Lukasz 
62270141561SBorawski.Lukasz } // namespace redfish
623