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 { 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 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 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 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 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 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 186 } // namespace ipmi 187 188 void registerBootstrapCredentialsOemCommands() 189 { 190 ipmi::registerHandler( 191 ipmi::prioOemBase, ipmi::groupNvidia, 192 ipmi::bootstrap_credentials_oem::cmdGetUsbVendorIdProductId, 193 ipmi::Privilege::Admin, ipmi::ipmiGetUsbVendorIdProductId); 194 195 ipmi::registerHandler( 196 ipmi::prioOemBase, ipmi::groupNvidia, 197 ipmi::bootstrap_credentials_oem::cmdGetUsbSerialNumber, 198 ipmi::Privilege::Admin, ipmi::ipmiGetUsbSerialNumber); 199 200 ipmi::registerHandler( 201 ipmi::prioOemBase, ipmi::groupNvidia, 202 ipmi::bootstrap_credentials_oem::cmdGetRedfishHostName, 203 ipmi::Privilege::Admin, ipmi::ipmiGetRedfishHostName); 204 205 ipmi::registerHandler( 206 ipmi::prioOemBase, ipmi::groupNvidia, 207 ipmi::bootstrap_credentials_oem::cmdGetIpmiChannelRfHi, 208 ipmi::Privilege::Admin, ipmi::ipmiGetIpmiChannelRfHi); 209 210 ipmi::registerHandler( 211 ipmi::prioOemBase, ipmi::groupNvidia, 212 ipmi::bootstrap_credentials_oem::cmdGetRedfishServiceUUID, 213 ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServiceUUID); 214 } 215