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