xref: /openbmc/phosphor-host-ipmid/oem/nvidia/bootstrap-credentials-oem-cmds.cpp (revision 400695c4c1d1c56b58bc22931c9b3bc60cfe0972)
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION &
3  * AFFILIATES. All rights reserved.
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "oemcommands.hpp"
8 
9 #include <ipmid/api.hpp>
10 #include <ipmid/types.hpp>
11 #include <ipmid/utils.hpp>
12 #include <nlohmann/json.hpp>
13 #include <phosphor-logging/lg2.hpp>
14 
15 #include <array>
16 #include <cstdint>
17 #include <fstream>
18 
19 void registerBootstrapCredentialsOemCommands() __attribute__((constructor));
20 
21 namespace ipmi
22 {
ipmiGetUsbVendorIdProductId(uint8_t type)23 ipmi::RspType<uint8_t, uint8_t> ipmiGetUsbVendorIdProductId(uint8_t type)
24 {
25     constexpr uint8_t descriptorVendorId = 1;
26     constexpr uint8_t descriptorProductId = 2;
27 
28     // IPMI OEM USB Linux Gadget info
29     constexpr uint16_t usbVendorId = 0x0525;
30     constexpr uint16_t usbProductId = 0xA4A2;
31 
32     if (type == descriptorVendorId)
33     {
34         return ipmi::responseSuccess(static_cast<uint8_t>(usbVendorId >> 8),
35                                      static_cast<uint8_t>(usbVendorId & 0xFF));
36     }
37     else if (type == descriptorProductId)
38     {
39         return ipmi::responseSuccess(static_cast<uint8_t>(usbProductId >> 8),
40                                      static_cast<uint8_t>(usbProductId & 0xFF));
41     }
42     return ipmi::responseInvalidFieldRequest();
43 }
44 
ipmiGetUsbSerialNumber()45 ipmi::RspType<ipmi::message::Payload> ipmiGetUsbSerialNumber()
46 {
47     static constexpr uint8_t usbSerialNumber = 0x00;
48     ipmi::message::Payload usbSerialNumberPayload;
49     usbSerialNumberPayload.pack(usbSerialNumber);
50     return ipmi::responseSuccess(usbSerialNumberPayload);
51 }
52 
ipmiGetRedfishHostName(ipmi::Context::ptr ctx)53 ipmi::RspType<ipmi::message::Payload> ipmiGetRedfishHostName(
54     ipmi::Context::ptr ctx)
55 {
56     std::string service{};
57     constexpr auto networkConfigObj = "/xyz/openbmc_project/network/config";
58     constexpr auto networkConfigIface =
59         "xyz.openbmc_project.Network.SystemConfiguration";
60     boost::system::error_code ec =
61         ipmi::getService(ctx, networkConfigIface, networkConfigObj, service);
62     if (ec)
63     {
64         lg2::error("ipmiGetRedfishHostName failed to get Network SystemConfig "
65                    "object: {STATUS}",
66                    "STATUS", ec.message());
67         return ipmi::responseResponseError();
68     }
69 
70     std::string hostName{};
71     ec = ipmi::getDbusProperty<std::string>(
72         ctx, service, networkConfigObj, networkConfigIface, "HostName",
73         hostName);
74     if (ec)
75     {
76         lg2::error("ipmiGetRedfishHostName failed to get HostName from Network "
77                    "SystemConfig service: {STATUS}",
78                    "STATUS", ec.message());
79         return ipmi::responseResponseError();
80     }
81     ipmi::message::Payload hostNamePayload;
82     hostNamePayload.pack(
83         std::vector<uint8_t>(hostName.begin(), hostName.end()));
84     return ipmi::responseSuccess(hostNamePayload);
85 }
86 
ipmiGetIpmiChannelRfHi()87 ipmi::RspType<uint8_t> ipmiGetIpmiChannelRfHi()
88 {
89     constexpr auto redfishHostInterfaceChannel = "usb0";
90     uint8_t chNum = ipmi::getChannelByName(redfishHostInterfaceChannel);
91     ChannelInfo chInfo{};
92     Cc compCode = ipmi::getChannelInfo(chNum, chInfo);
93     if (compCode != ipmi::ccSuccess)
94     {
95         lg2::error(
96             "ipmiGetIpmiChannelRfHi failed for channel {CHANNEL} with error {ERROR}",
97             "CHANNEL", chNum, "ERROR", compCode);
98         return ipmi::responseUnspecifiedError();
99     }
100 
101     if (chInfo.mediumType !=
102             static_cast<uint8_t>(EChannelMediumType::lan8032) ||
103         chInfo.protocolType !=
104             static_cast<uint8_t>(EChannelProtocolType::ipmbV10) ||
105         chInfo.sessionSupported !=
106             static_cast<uint8_t>(EChannelSessSupported::multi) ||
107         chInfo.isIpmi != true)
108     {
109         lg2::error(
110             "ipmiGetIpmiChannelRfHi: channel {CHANNEL} lacks required config",
111             "CHANNEL", chNum);
112         return responseSensorInvalid();
113     }
114     return ipmi::responseSuccess(static_cast<uint8_t>(chNum));
115 }
116 
getRfUuid(std::string & rfUuid)117 bool getRfUuid(std::string& rfUuid)
118 {
119     constexpr const char* bmcwebPersistentDataFile =
120         "/home/root/bmcweb_persistent_data.json";
121     std::ifstream f(bmcwebPersistentDataFile);
122     if (!f.is_open())
123     {
124         lg2::error("Failed to open {FILE}", "FILE", bmcwebPersistentDataFile);
125         return false;
126     }
127     auto data = nlohmann::json::parse(f, nullptr, false);
128     if (data.is_discarded())
129     {
130         lg2::error("Failed to parse {FILE}", "FILE", bmcwebPersistentDataFile);
131         return false;
132     }
133 
134     if (auto it = data.find("system_uuid"); it != data.end() && it->is_string())
135     {
136         rfUuid = *it;
137         return true;
138     }
139 
140     lg2::error("system_uuid missing in {FILE}", "FILE",
141                bmcwebPersistentDataFile);
142     return false;
143 }
144 
ipmiGetRedfishServiceUUID()145 ipmi::RspType<std::vector<uint8_t>> ipmiGetRedfishServiceUUID()
146 {
147     std::string rfUuid;
148     bool ret = getRfUuid(rfUuid);
149     if (!ret)
150     {
151         lg2::error(
152             "ipmiGetRedfishServiceUUID: Error reading Redfish Service UUID File.");
153         return ipmi::responseResponseError();
154     }
155 
156     // As per Redfish Host Interface Spec v1.3.0
157     // The Redfish UUID is 16byte and should be represented as below:
158     // Ex: {00112233-4455-6677-8899-AABBCCDDEEFF}
159     // 0x33 0x22 0x11 0x00 0x55 0x44 0x77 0x66 0x88 0x99 0xAA 0xBB 0xCC 0xDD
160     // 0xEE 0xFF
161 
162     std::vector<uint8_t> resBuf;
163     std::vector<std::string> groups = ipmi::split(rfUuid, '-');
164 
165     for (size_t i = 0; i < groups.size(); ++i)
166     {
167         auto group = groups[i];
168         if (i < 3)
169         {
170             std::reverse(group.begin(), group.end());
171         }
172 
173         for (size_t j = 0; j < group.size(); j += 2)
174         {
175             if (i < 3)
176             {
177                 std::swap(group[j], group[j + 1]);
178             }
179             resBuf.push_back(static_cast<uint8_t>(
180                 std::stoi(group.substr(j, 2), nullptr, 16)));
181         }
182     }
183     return ipmi::responseSuccess(resBuf);
184 }
185 
ipmiGetRedfishServicePort()186 ipmi::RspType<uint16_t> ipmiGetRedfishServicePort()
187 {
188     constexpr uint16_t redfishPort = 443;
189     return ipmi::responseSuccess(htons(redfishPort));
190 }
191 
192 } // namespace ipmi
193 
registerBootstrapCredentialsOemCommands()194 void registerBootstrapCredentialsOemCommands()
195 {
196     ipmi::registerHandler(
197         ipmi::prioOemBase, ipmi::groupNvidia,
198         ipmi::bootstrap_credentials_oem::cmdGetUsbVendorIdProductId,
199         ipmi::Privilege::Admin, ipmi::ipmiGetUsbVendorIdProductId);
200 
201     ipmi::registerHandler(
202         ipmi::prioOemBase, ipmi::groupNvidia,
203         ipmi::bootstrap_credentials_oem::cmdGetUsbSerialNumber,
204         ipmi::Privilege::Admin, ipmi::ipmiGetUsbSerialNumber);
205 
206     ipmi::registerHandler(
207         ipmi::prioOemBase, ipmi::groupNvidia,
208         ipmi::bootstrap_credentials_oem::cmdGetRedfishHostName,
209         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishHostName);
210 
211     ipmi::registerHandler(
212         ipmi::prioOemBase, ipmi::groupNvidia,
213         ipmi::bootstrap_credentials_oem::cmdGetIpmiChannelRfHi,
214         ipmi::Privilege::Admin, ipmi::ipmiGetIpmiChannelRfHi);
215 
216     ipmi::registerHandler(
217         ipmi::prioOemBase, ipmi::groupNvidia,
218         ipmi::bootstrap_credentials_oem::cmdGetRedfishServiceUUID,
219         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServiceUUID);
220 
221     ipmi::registerHandler(
222         ipmi::prioOemBase, ipmi::groupNvidia,
223         ipmi::bootstrap_credentials_oem::cmdGetRedfishServicePort,
224         ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServicePort);
225 }
226