xref: /openbmc/phosphor-host-ipmid/oem/nvidia/bootstrap-credentials-oem-cmds.cpp (revision 400695c4c1d1c56b58bc22931c9b3bc60cfe0972)
1bffaa110SPrithvi Pai /*
2bffaa110SPrithvi Pai  * SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION &
3bffaa110SPrithvi Pai  * AFFILIATES. All rights reserved.
4bffaa110SPrithvi Pai  * SPDX-License-Identifier: Apache-2.0
5bffaa110SPrithvi Pai  */
6bffaa110SPrithvi Pai 
7bffaa110SPrithvi Pai #include "oemcommands.hpp"
8bffaa110SPrithvi Pai 
9bffaa110SPrithvi Pai #include <ipmid/api.hpp>
10bffaa110SPrithvi Pai #include <ipmid/types.hpp>
116823fd46SPrithvi Pai #include <ipmid/utils.hpp>
12c1e7b5c3SPrithvi Pai #include <nlohmann/json.hpp>
136823fd46SPrithvi Pai #include <phosphor-logging/lg2.hpp>
14bffaa110SPrithvi Pai 
15c1e7b5c3SPrithvi Pai #include <array>
16bffaa110SPrithvi Pai #include <cstdint>
17c1e7b5c3SPrithvi Pai #include <fstream>
18bffaa110SPrithvi Pai 
19bffaa110SPrithvi Pai void registerBootstrapCredentialsOemCommands() __attribute__((constructor));
20bffaa110SPrithvi Pai 
21bffaa110SPrithvi Pai namespace ipmi
22bffaa110SPrithvi Pai {
ipmiGetUsbVendorIdProductId(uint8_t type)23bffaa110SPrithvi Pai ipmi::RspType<uint8_t, uint8_t> ipmiGetUsbVendorIdProductId(uint8_t type)
24bffaa110SPrithvi Pai {
25bffaa110SPrithvi Pai     constexpr uint8_t descriptorVendorId = 1;
26bffaa110SPrithvi Pai     constexpr uint8_t descriptorProductId = 2;
27bffaa110SPrithvi Pai 
28bffaa110SPrithvi Pai     // IPMI OEM USB Linux Gadget info
29bffaa110SPrithvi Pai     constexpr uint16_t usbVendorId = 0x0525;
30bffaa110SPrithvi Pai     constexpr uint16_t usbProductId = 0xA4A2;
31bffaa110SPrithvi Pai 
32bffaa110SPrithvi Pai     if (type == descriptorVendorId)
33bffaa110SPrithvi Pai     {
34bffaa110SPrithvi Pai         return ipmi::responseSuccess(static_cast<uint8_t>(usbVendorId >> 8),
35bffaa110SPrithvi Pai                                      static_cast<uint8_t>(usbVendorId & 0xFF));
36bffaa110SPrithvi Pai     }
37bffaa110SPrithvi Pai     else if (type == descriptorProductId)
38bffaa110SPrithvi Pai     {
39bffaa110SPrithvi Pai         return ipmi::responseSuccess(static_cast<uint8_t>(usbProductId >> 8),
40bffaa110SPrithvi Pai                                      static_cast<uint8_t>(usbProductId & 0xFF));
41bffaa110SPrithvi Pai     }
42bffaa110SPrithvi Pai     return ipmi::responseInvalidFieldRequest();
43bffaa110SPrithvi Pai }
44bffaa110SPrithvi Pai 
ipmiGetUsbSerialNumber()456bf35ee6SPrithvi Pai ipmi::RspType<ipmi::message::Payload> ipmiGetUsbSerialNumber()
466bf35ee6SPrithvi Pai {
476bf35ee6SPrithvi Pai     static constexpr uint8_t usbSerialNumber = 0x00;
486bf35ee6SPrithvi Pai     ipmi::message::Payload usbSerialNumberPayload;
496bf35ee6SPrithvi Pai     usbSerialNumberPayload.pack(usbSerialNumber);
506bf35ee6SPrithvi Pai     return ipmi::responseSuccess(usbSerialNumberPayload);
516bf35ee6SPrithvi Pai }
526bf35ee6SPrithvi Pai 
ipmiGetRedfishHostName(ipmi::Context::ptr ctx)536823fd46SPrithvi Pai ipmi::RspType<ipmi::message::Payload> ipmiGetRedfishHostName(
546823fd46SPrithvi Pai     ipmi::Context::ptr ctx)
556823fd46SPrithvi Pai {
566823fd46SPrithvi Pai     std::string service{};
576823fd46SPrithvi Pai     constexpr auto networkConfigObj = "/xyz/openbmc_project/network/config";
586823fd46SPrithvi Pai     constexpr auto networkConfigIface =
596823fd46SPrithvi Pai         "xyz.openbmc_project.Network.SystemConfiguration";
606823fd46SPrithvi Pai     boost::system::error_code ec =
616823fd46SPrithvi Pai         ipmi::getService(ctx, networkConfigIface, networkConfigObj, service);
626823fd46SPrithvi Pai     if (ec)
636823fd46SPrithvi Pai     {
646823fd46SPrithvi Pai         lg2::error("ipmiGetRedfishHostName failed to get Network SystemConfig "
656823fd46SPrithvi Pai                    "object: {STATUS}",
666823fd46SPrithvi Pai                    "STATUS", ec.message());
676823fd46SPrithvi Pai         return ipmi::responseResponseError();
686823fd46SPrithvi Pai     }
696823fd46SPrithvi Pai 
706823fd46SPrithvi Pai     std::string hostName{};
716823fd46SPrithvi Pai     ec = ipmi::getDbusProperty<std::string>(
726823fd46SPrithvi Pai         ctx, service, networkConfigObj, networkConfigIface, "HostName",
736823fd46SPrithvi Pai         hostName);
746823fd46SPrithvi Pai     if (ec)
756823fd46SPrithvi Pai     {
766823fd46SPrithvi Pai         lg2::error("ipmiGetRedfishHostName failed to get HostName from Network "
776823fd46SPrithvi Pai                    "SystemConfig service: {STATUS}",
786823fd46SPrithvi Pai                    "STATUS", ec.message());
796823fd46SPrithvi Pai         return ipmi::responseResponseError();
806823fd46SPrithvi Pai     }
816823fd46SPrithvi Pai     ipmi::message::Payload hostNamePayload;
826823fd46SPrithvi Pai     hostNamePayload.pack(
836823fd46SPrithvi Pai         std::vector<uint8_t>(hostName.begin(), hostName.end()));
846823fd46SPrithvi Pai     return ipmi::responseSuccess(hostNamePayload);
856823fd46SPrithvi Pai }
86529d31c7SPrithvi Pai 
ipmiGetIpmiChannelRfHi()87529d31c7SPrithvi Pai ipmi::RspType<uint8_t> ipmiGetIpmiChannelRfHi()
88529d31c7SPrithvi Pai {
89529d31c7SPrithvi Pai     constexpr auto redfishHostInterfaceChannel = "usb0";
90529d31c7SPrithvi Pai     uint8_t chNum = ipmi::getChannelByName(redfishHostInterfaceChannel);
91529d31c7SPrithvi Pai     ChannelInfo chInfo{};
92529d31c7SPrithvi Pai     Cc compCode = ipmi::getChannelInfo(chNum, chInfo);
93529d31c7SPrithvi Pai     if (compCode != ipmi::ccSuccess)
94529d31c7SPrithvi Pai     {
95529d31c7SPrithvi Pai         lg2::error(
96529d31c7SPrithvi Pai             "ipmiGetIpmiChannelRfHi failed for channel {CHANNEL} with error {ERROR}",
97529d31c7SPrithvi Pai             "CHANNEL", chNum, "ERROR", compCode);
98529d31c7SPrithvi Pai         return ipmi::responseUnspecifiedError();
99529d31c7SPrithvi Pai     }
100529d31c7SPrithvi Pai 
101529d31c7SPrithvi Pai     if (chInfo.mediumType !=
102529d31c7SPrithvi Pai             static_cast<uint8_t>(EChannelMediumType::lan8032) ||
103529d31c7SPrithvi Pai         chInfo.protocolType !=
104529d31c7SPrithvi Pai             static_cast<uint8_t>(EChannelProtocolType::ipmbV10) ||
105529d31c7SPrithvi Pai         chInfo.sessionSupported !=
106529d31c7SPrithvi Pai             static_cast<uint8_t>(EChannelSessSupported::multi) ||
107529d31c7SPrithvi Pai         chInfo.isIpmi != true)
108529d31c7SPrithvi Pai     {
109529d31c7SPrithvi Pai         lg2::error(
110529d31c7SPrithvi Pai             "ipmiGetIpmiChannelRfHi: channel {CHANNEL} lacks required config",
111529d31c7SPrithvi Pai             "CHANNEL", chNum);
112529d31c7SPrithvi Pai         return responseSensorInvalid();
113529d31c7SPrithvi Pai     }
114529d31c7SPrithvi Pai     return ipmi::responseSuccess(static_cast<uint8_t>(chNum));
115529d31c7SPrithvi Pai }
116529d31c7SPrithvi Pai 
getRfUuid(std::string & rfUuid)117c1e7b5c3SPrithvi Pai bool getRfUuid(std::string& rfUuid)
118c1e7b5c3SPrithvi Pai {
119c1e7b5c3SPrithvi Pai     constexpr const char* bmcwebPersistentDataFile =
120c1e7b5c3SPrithvi Pai         "/home/root/bmcweb_persistent_data.json";
121c1e7b5c3SPrithvi Pai     std::ifstream f(bmcwebPersistentDataFile);
122c1e7b5c3SPrithvi Pai     if (!f.is_open())
123c1e7b5c3SPrithvi Pai     {
124c1e7b5c3SPrithvi Pai         lg2::error("Failed to open {FILE}", "FILE", bmcwebPersistentDataFile);
125c1e7b5c3SPrithvi Pai         return false;
126c1e7b5c3SPrithvi Pai     }
127c1e7b5c3SPrithvi Pai     auto data = nlohmann::json::parse(f, nullptr, false);
128c1e7b5c3SPrithvi Pai     if (data.is_discarded())
129c1e7b5c3SPrithvi Pai     {
130c1e7b5c3SPrithvi Pai         lg2::error("Failed to parse {FILE}", "FILE", bmcwebPersistentDataFile);
131c1e7b5c3SPrithvi Pai         return false;
132c1e7b5c3SPrithvi Pai     }
133c1e7b5c3SPrithvi Pai 
134c1e7b5c3SPrithvi Pai     if (auto it = data.find("system_uuid"); it != data.end() && it->is_string())
135c1e7b5c3SPrithvi Pai     {
136c1e7b5c3SPrithvi Pai         rfUuid = *it;
137c1e7b5c3SPrithvi Pai         return true;
138c1e7b5c3SPrithvi Pai     }
139c1e7b5c3SPrithvi Pai 
140c1e7b5c3SPrithvi Pai     lg2::error("system_uuid missing in {FILE}", "FILE",
141c1e7b5c3SPrithvi Pai                bmcwebPersistentDataFile);
142c1e7b5c3SPrithvi Pai     return false;
143c1e7b5c3SPrithvi Pai }
144c1e7b5c3SPrithvi Pai 
ipmiGetRedfishServiceUUID()145c1e7b5c3SPrithvi Pai ipmi::RspType<std::vector<uint8_t>> ipmiGetRedfishServiceUUID()
146c1e7b5c3SPrithvi Pai {
147c1e7b5c3SPrithvi Pai     std::string rfUuid;
148c1e7b5c3SPrithvi Pai     bool ret = getRfUuid(rfUuid);
149c1e7b5c3SPrithvi Pai     if (!ret)
150c1e7b5c3SPrithvi Pai     {
151c1e7b5c3SPrithvi Pai         lg2::error(
152c1e7b5c3SPrithvi Pai             "ipmiGetRedfishServiceUUID: Error reading Redfish Service UUID File.");
153c1e7b5c3SPrithvi Pai         return ipmi::responseResponseError();
154c1e7b5c3SPrithvi Pai     }
155c1e7b5c3SPrithvi Pai 
156c1e7b5c3SPrithvi Pai     // As per Redfish Host Interface Spec v1.3.0
157c1e7b5c3SPrithvi Pai     // The Redfish UUID is 16byte and should be represented as below:
158c1e7b5c3SPrithvi Pai     // Ex: {00112233-4455-6677-8899-AABBCCDDEEFF}
159c1e7b5c3SPrithvi Pai     // 0x33 0x22 0x11 0x00 0x55 0x44 0x77 0x66 0x88 0x99 0xAA 0xBB 0xCC 0xDD
160c1e7b5c3SPrithvi Pai     // 0xEE 0xFF
161c1e7b5c3SPrithvi Pai 
162c1e7b5c3SPrithvi Pai     std::vector<uint8_t> resBuf;
163c1e7b5c3SPrithvi Pai     std::vector<std::string> groups = ipmi::split(rfUuid, '-');
164c1e7b5c3SPrithvi Pai 
165c1e7b5c3SPrithvi Pai     for (size_t i = 0; i < groups.size(); ++i)
166c1e7b5c3SPrithvi Pai     {
167c1e7b5c3SPrithvi Pai         auto group = groups[i];
168c1e7b5c3SPrithvi Pai         if (i < 3)
169c1e7b5c3SPrithvi Pai         {
170c1e7b5c3SPrithvi Pai             std::reverse(group.begin(), group.end());
171c1e7b5c3SPrithvi Pai         }
172c1e7b5c3SPrithvi Pai 
173c1e7b5c3SPrithvi Pai         for (size_t j = 0; j < group.size(); j += 2)
174c1e7b5c3SPrithvi Pai         {
175c1e7b5c3SPrithvi Pai             if (i < 3)
176c1e7b5c3SPrithvi Pai             {
177c1e7b5c3SPrithvi Pai                 std::swap(group[j], group[j + 1]);
178c1e7b5c3SPrithvi Pai             }
179c1e7b5c3SPrithvi Pai             resBuf.push_back(static_cast<uint8_t>(
180c1e7b5c3SPrithvi Pai                 std::stoi(group.substr(j, 2), nullptr, 16)));
181c1e7b5c3SPrithvi Pai         }
182c1e7b5c3SPrithvi Pai     }
183c1e7b5c3SPrithvi Pai     return ipmi::responseSuccess(resBuf);
184c1e7b5c3SPrithvi Pai }
185c1e7b5c3SPrithvi Pai 
ipmiGetRedfishServicePort()186*400695c4SPrithvi Pai ipmi::RspType<uint16_t> ipmiGetRedfishServicePort()
187*400695c4SPrithvi Pai {
188*400695c4SPrithvi Pai     constexpr uint16_t redfishPort = 443;
189*400695c4SPrithvi Pai     return ipmi::responseSuccess(htons(redfishPort));
190*400695c4SPrithvi Pai }
191*400695c4SPrithvi Pai 
192bffaa110SPrithvi Pai } // namespace ipmi
193bffaa110SPrithvi Pai 
registerBootstrapCredentialsOemCommands()194bffaa110SPrithvi Pai void registerBootstrapCredentialsOemCommands()
195bffaa110SPrithvi Pai {
196bffaa110SPrithvi Pai     ipmi::registerHandler(
197bffaa110SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
198bffaa110SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetUsbVendorIdProductId,
199bffaa110SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetUsbVendorIdProductId);
2006bf35ee6SPrithvi Pai 
2016bf35ee6SPrithvi Pai     ipmi::registerHandler(
2026bf35ee6SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
2036bf35ee6SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetUsbSerialNumber,
2046bf35ee6SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetUsbSerialNumber);
2056823fd46SPrithvi Pai 
2066823fd46SPrithvi Pai     ipmi::registerHandler(
2076823fd46SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
2086823fd46SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetRedfishHostName,
2096823fd46SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishHostName);
210529d31c7SPrithvi Pai 
211529d31c7SPrithvi Pai     ipmi::registerHandler(
212529d31c7SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
213529d31c7SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetIpmiChannelRfHi,
214529d31c7SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetIpmiChannelRfHi);
215c1e7b5c3SPrithvi Pai 
216c1e7b5c3SPrithvi Pai     ipmi::registerHandler(
217c1e7b5c3SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
218c1e7b5c3SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetRedfishServiceUUID,
219c1e7b5c3SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServiceUUID);
220*400695c4SPrithvi Pai 
221*400695c4SPrithvi Pai     ipmi::registerHandler(
222*400695c4SPrithvi Pai         ipmi::prioOemBase, ipmi::groupNvidia,
223*400695c4SPrithvi Pai         ipmi::bootstrap_credentials_oem::cmdGetRedfishServicePort,
224*400695c4SPrithvi Pai         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServicePort);
225bffaa110SPrithvi Pai }
226