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 6*d7857201SEd Tanous #include "bmcweb_config.h" 7*d7857201SEd Tanous 83ccb3adbSEd Tanous #include "app.hpp" 9*d7857201SEd Tanous #include "async_resp.hpp" 10*d7857201SEd Tanous #include "dbus_singleton.hpp" 113ccb3adbSEd Tanous #include "dbus_utility.hpp" 123a8a0088SKowalski, Kamil #include "error_messages.hpp" 13539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 14*d7857201SEd Tanous #include "http_request.hpp" 15*d7857201SEd Tanous #include "logging.hpp" 16*d7857201SEd Tanous #include "privileges.hpp" 173ccb3adbSEd Tanous #include "query.hpp" 18b4bec66bSAbhishek Patel #include "redfish_util.hpp" 193ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 20*d7857201SEd Tanous #include "utils/dbus_utils.hpp" 213ccb3adbSEd Tanous #include "utils/json_utils.hpp" 223ccb3adbSEd Tanous #include "utils/stl_utils.hpp" 2370141561SBorawski.Lukasz 24*d7857201SEd Tanous #include <unistd.h> 25*d7857201SEd Tanous 26*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 27*d7857201SEd Tanous #include <boost/beast/http/status.hpp> 28*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 29e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 30253f11b8SEd Tanous #include <boost/url/format.hpp> 31*d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 321214b7e7SGunnar Mills 33e99073f5SGeorge Liu #include <array> 34*d7857201SEd Tanous #include <cstddef> 35*d7857201SEd Tanous #include <functional> 36*d7857201SEd Tanous #include <memory> 371214b7e7SGunnar Mills #include <optional> 38*d7857201SEd Tanous #include <string> 39e99073f5SGeorge Liu #include <string_view> 40*d7857201SEd Tanous #include <tuple> 41*d7857201SEd 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 3024f48d5f6SEd Tanous inline void 303287ece64SGeorge Liu handleNTPServersPatch(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 4064f48d5f6SEd Tanous inline void 4074f48d5f6SEd Tanous handleProtocolEnabled(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 4554f48d5f6SEd Tanous inline void 4564f48d5f6SEd Tanous getNTPProtocolEnabled(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