#include "config.h" #include "systemintfcmds.hpp" #include "host-cmd-manager.hpp" #include "host-interface.hpp" #include <ipmid-host/cmd.hpp> #include <ipmid/api.hpp> #include <nlohmann/json.hpp> #include <cstring> #include <fstream> void register_netfn_app_functions() __attribute__((constructor)); using namespace sdbusplus::server::xyz::openbmc_project::control; // For accessing Host command manager using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>; extern cmdManagerPtr& ipmid_get_host_cmd_manager(); //------------------------------------------------------------------- // Called by Host post response from Get_Message_Flags //------------------------------------------------------------------- ipmi::RspType<uint16_t, // id uint8_t, // type uint24_t, // manuf_id uint32_t, // timestamp uint8_t, // netfun uint8_t, // cmd std::array<uint8_t, 4> // data > ipmiAppReadEventBuffer(ipmi::Context::ptr& ctx) { // require this to be limited to system interface if (ctx->channel != ipmi::channelSystemIface) { return ipmi::responseInvalidCommand(); } constexpr uint16_t selOemId = 0x5555; constexpr uint8_t selRecordTypeOem = 0xc0; // read manufacturer ID from dev_id file static uint24_t manufId{}; if (!manufId) { const char* filename = "/usr/share/ipmi-providers/dev_id.json"; std::ifstream devIdFile(filename); if (devIdFile.is_open()) { auto data = nlohmann::json::parse(devIdFile, nullptr, false); if (!data.is_discarded()) { manufId = data.value("manuf_id", 0); } } } constexpr uint32_t timestamp{0}; // per IPMI spec NetFuntion for OEM constexpr uint8_t netfun = 0x3a; // Read from the Command Manager queue. What gets returned is a // pair of <command, data> that can be directly used here const auto& [cmd, data0] = ipmid_get_host_cmd_manager()->getNextCommand(); constexpr uint8_t dataUnused = 0xff; return ipmi::responseSuccess( selOemId, selRecordTypeOem, manufId, timestamp, netfun, cmd, std::to_array<uint8_t>({data0, dataUnused, dataUnused, dataUnused})); } //--------------------------------------------------------------------- // Called by Host on seeing a SMS_ATN bit set. Return a hardcoded // value of 0x0 to indicate Event Message Buffer is not supported //------------------------------------------------------------------- ipmi::RspType<uint8_t> ipmiAppGetMessageFlags() { // From IPMI spec V2.0 for Get Message Flags Command : // bit:[1] from LSB : 1b = Event Message Buffer Full. // Return as 0 if Event Message Buffer is not supported, // or when the Event Message buffer is disabled. // This path is used to communicate messages to the host // from within the phosphor::host::command::Manager constexpr uint8_t setEventMsgBufferNotSupported = 0x0; return ipmi::responseSuccess(setEventMsgBufferNotSupported); } ipmi::RspType<bool, // Receive Message Queue Interrupt Enabled bool, // Event Message Buffer Full Interrupt Enabled bool, // Event Message Buffer Enabled bool, // System Event Logging Enabled uint1_t, // Reserved bool, // OEM 0 enabled bool, // OEM 1 enabled bool // OEM 2 enabled > ipmiAppGetBMCGlobalEnable() { return ipmi::responseSuccess(true, false, false, true, 0, false, false, false); } ipmi::RspType<> ipmiAppSetBMCGlobalEnable( ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled, bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled, bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled, bool OEM1Enabled, bool OEM2Enabled) { ipmi::ChannelInfo chInfo; if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess) { phosphor::logging::log<phosphor::logging::level::ERR>( "Failed to get Channel Info", phosphor::logging::entry("CHANNEL=%d", ctx->channel)); return ipmi::responseUnspecifiedError(); } if (chInfo.mediumType != static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) { phosphor::logging::log<phosphor::logging::level::ERR>( "Error - supported only in system interface"); return ipmi::responseCommandNotAvailable(); } // Recv Message Queue and SEL are enabled by default. // Event Message buffer are disabled by default (not supported). // Any request that try to change the mask will be rejected if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable || eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled || OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved) { return ipmi::responseInvalidFieldRequest(); } return ipmi::responseSuccess(); } namespace { // Static storage to keep the object alive during process life std::unique_ptr<phosphor::host::command::Host> host __attribute__((init_priority(101))); std::unique_ptr<sdbusplus::server::manager_t> objManager __attribute__((init_priority(101))); } // namespace void register_netfn_app_functions() { // <Read Event Message Buffer> ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, ipmi::app::cmdReadEventMessageBuffer, ipmi::Privilege::Admin, ipmiAppReadEventBuffer); // <Set BMC Global Enables> ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, ipmi::app::cmdSetBmcGlobalEnables, ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable); // <Get BMC Global Enables> ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, ipmi::app::cmdGetBmcGlobalEnables, ipmi::Privilege::User, ipmiAppGetBMCGlobalEnable); // <Get Message Flags> ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin, ipmiAppGetMessageFlags); // Create new xyz.openbmc_project.host object on the bus auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0'; std::unique_ptr<sdbusplus::asio::connection>& sdbusp = ipmid_get_sdbus_plus_handler(); // Add sdbusplus ObjectManager. objManager = std::make_unique<sdbusplus::server::manager_t>( *sdbusp, CONTROL_HOST_OBJ_MGR); host = std::make_unique<phosphor::host::command::Host>(*sdbusp, objPath.c_str()); sdbusp->request_name(CONTROL_HOST_BUSNAME); return; }