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