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> 12*c1e7b5c3SPrithvi Pai #include <nlohmann/json.hpp> 136823fd46SPrithvi Pai #include <phosphor-logging/lg2.hpp> 14bffaa110SPrithvi Pai 15*c1e7b5c3SPrithvi Pai #include <array> 16bffaa110SPrithvi Pai #include <cstdint> 17*c1e7b5c3SPrithvi Pai #include <fstream> 18bffaa110SPrithvi Pai 19bffaa110SPrithvi Pai void registerBootstrapCredentialsOemCommands() __attribute__((constructor)); 20bffaa110SPrithvi Pai 21bffaa110SPrithvi Pai namespace ipmi 22bffaa110SPrithvi Pai { 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 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 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 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 117*c1e7b5c3SPrithvi Pai bool getRfUuid(std::string& rfUuid) 118*c1e7b5c3SPrithvi Pai { 119*c1e7b5c3SPrithvi Pai constexpr const char* bmcwebPersistentDataFile = 120*c1e7b5c3SPrithvi Pai "/home/root/bmcweb_persistent_data.json"; 121*c1e7b5c3SPrithvi Pai std::ifstream f(bmcwebPersistentDataFile); 122*c1e7b5c3SPrithvi Pai if (!f.is_open()) 123*c1e7b5c3SPrithvi Pai { 124*c1e7b5c3SPrithvi Pai lg2::error("Failed to open {FILE}", "FILE", bmcwebPersistentDataFile); 125*c1e7b5c3SPrithvi Pai return false; 126*c1e7b5c3SPrithvi Pai } 127*c1e7b5c3SPrithvi Pai auto data = nlohmann::json::parse(f, nullptr, false); 128*c1e7b5c3SPrithvi Pai if (data.is_discarded()) 129*c1e7b5c3SPrithvi Pai { 130*c1e7b5c3SPrithvi Pai lg2::error("Failed to parse {FILE}", "FILE", bmcwebPersistentDataFile); 131*c1e7b5c3SPrithvi Pai return false; 132*c1e7b5c3SPrithvi Pai } 133*c1e7b5c3SPrithvi Pai 134*c1e7b5c3SPrithvi Pai if (auto it = data.find("system_uuid"); it != data.end() && it->is_string()) 135*c1e7b5c3SPrithvi Pai { 136*c1e7b5c3SPrithvi Pai rfUuid = *it; 137*c1e7b5c3SPrithvi Pai return true; 138*c1e7b5c3SPrithvi Pai } 139*c1e7b5c3SPrithvi Pai 140*c1e7b5c3SPrithvi Pai lg2::error("system_uuid missing in {FILE}", "FILE", 141*c1e7b5c3SPrithvi Pai bmcwebPersistentDataFile); 142*c1e7b5c3SPrithvi Pai return false; 143*c1e7b5c3SPrithvi Pai } 144*c1e7b5c3SPrithvi Pai 145*c1e7b5c3SPrithvi Pai ipmi::RspType<std::vector<uint8_t>> ipmiGetRedfishServiceUUID() 146*c1e7b5c3SPrithvi Pai { 147*c1e7b5c3SPrithvi Pai std::string rfUuid; 148*c1e7b5c3SPrithvi Pai bool ret = getRfUuid(rfUuid); 149*c1e7b5c3SPrithvi Pai if (!ret) 150*c1e7b5c3SPrithvi Pai { 151*c1e7b5c3SPrithvi Pai lg2::error( 152*c1e7b5c3SPrithvi Pai "ipmiGetRedfishServiceUUID: Error reading Redfish Service UUID File."); 153*c1e7b5c3SPrithvi Pai return ipmi::responseResponseError(); 154*c1e7b5c3SPrithvi Pai } 155*c1e7b5c3SPrithvi Pai 156*c1e7b5c3SPrithvi Pai // As per Redfish Host Interface Spec v1.3.0 157*c1e7b5c3SPrithvi Pai // The Redfish UUID is 16byte and should be represented as below: 158*c1e7b5c3SPrithvi Pai // Ex: {00112233-4455-6677-8899-AABBCCDDEEFF} 159*c1e7b5c3SPrithvi Pai // 0x33 0x22 0x11 0x00 0x55 0x44 0x77 0x66 0x88 0x99 0xAA 0xBB 0xCC 0xDD 160*c1e7b5c3SPrithvi Pai // 0xEE 0xFF 161*c1e7b5c3SPrithvi Pai 162*c1e7b5c3SPrithvi Pai std::vector<uint8_t> resBuf; 163*c1e7b5c3SPrithvi Pai std::vector<std::string> groups = ipmi::split(rfUuid, '-'); 164*c1e7b5c3SPrithvi Pai 165*c1e7b5c3SPrithvi Pai for (size_t i = 0; i < groups.size(); ++i) 166*c1e7b5c3SPrithvi Pai { 167*c1e7b5c3SPrithvi Pai auto group = groups[i]; 168*c1e7b5c3SPrithvi Pai if (i < 3) 169*c1e7b5c3SPrithvi Pai { 170*c1e7b5c3SPrithvi Pai std::reverse(group.begin(), group.end()); 171*c1e7b5c3SPrithvi Pai } 172*c1e7b5c3SPrithvi Pai 173*c1e7b5c3SPrithvi Pai for (size_t j = 0; j < group.size(); j += 2) 174*c1e7b5c3SPrithvi Pai { 175*c1e7b5c3SPrithvi Pai if (i < 3) 176*c1e7b5c3SPrithvi Pai { 177*c1e7b5c3SPrithvi Pai std::swap(group[j], group[j + 1]); 178*c1e7b5c3SPrithvi Pai } 179*c1e7b5c3SPrithvi Pai resBuf.push_back(static_cast<uint8_t>( 180*c1e7b5c3SPrithvi Pai std::stoi(group.substr(j, 2), nullptr, 16))); 181*c1e7b5c3SPrithvi Pai } 182*c1e7b5c3SPrithvi Pai } 183*c1e7b5c3SPrithvi Pai return ipmi::responseSuccess(resBuf); 184*c1e7b5c3SPrithvi Pai } 185*c1e7b5c3SPrithvi Pai 186bffaa110SPrithvi Pai } // namespace ipmi 187bffaa110SPrithvi Pai 188bffaa110SPrithvi Pai void registerBootstrapCredentialsOemCommands() 189bffaa110SPrithvi Pai { 190bffaa110SPrithvi Pai ipmi::registerHandler( 191bffaa110SPrithvi Pai ipmi::prioOemBase, ipmi::groupNvidia, 192bffaa110SPrithvi Pai ipmi::bootstrap_credentials_oem::cmdGetUsbVendorIdProductId, 193bffaa110SPrithvi Pai ipmi::Privilege::Admin, ipmi::ipmiGetUsbVendorIdProductId); 1946bf35ee6SPrithvi Pai 1956bf35ee6SPrithvi Pai ipmi::registerHandler( 1966bf35ee6SPrithvi Pai ipmi::prioOemBase, ipmi::groupNvidia, 1976bf35ee6SPrithvi Pai ipmi::bootstrap_credentials_oem::cmdGetUsbSerialNumber, 1986bf35ee6SPrithvi Pai ipmi::Privilege::Admin, ipmi::ipmiGetUsbSerialNumber); 1996823fd46SPrithvi Pai 2006823fd46SPrithvi Pai ipmi::registerHandler( 2016823fd46SPrithvi Pai ipmi::prioOemBase, ipmi::groupNvidia, 2026823fd46SPrithvi Pai ipmi::bootstrap_credentials_oem::cmdGetRedfishHostName, 2036823fd46SPrithvi Pai ipmi::Privilege::Admin, ipmi::ipmiGetRedfishHostName); 204529d31c7SPrithvi Pai 205529d31c7SPrithvi Pai ipmi::registerHandler( 206529d31c7SPrithvi Pai ipmi::prioOemBase, ipmi::groupNvidia, 207529d31c7SPrithvi Pai ipmi::bootstrap_credentials_oem::cmdGetIpmiChannelRfHi, 208529d31c7SPrithvi Pai ipmi::Privilege::Admin, ipmi::ipmiGetIpmiChannelRfHi); 209*c1e7b5c3SPrithvi Pai 210*c1e7b5c3SPrithvi Pai ipmi::registerHandler( 211*c1e7b5c3SPrithvi Pai ipmi::prioOemBase, ipmi::groupNvidia, 212*c1e7b5c3SPrithvi Pai ipmi::bootstrap_credentials_oem::cmdGetRedfishServiceUUID, 213*c1e7b5c3SPrithvi Pai ipmi::Privilege::Admin, ipmi::ipmiGetRedfishServiceUUID); 214bffaa110SPrithvi Pai } 215