1 #include "config.h" 2 3 #include "systemintfcmds.hpp" 4 5 #include "host-cmd-manager.hpp" 6 #include "host-interface.hpp" 7 8 #include <ipmid-host/cmd.hpp> 9 #include <ipmid/api.hpp> 10 #include <nlohmann/json.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 13 #include <cstring> 14 #include <fstream> 15 16 void register_netfn_app_functions() __attribute__((constructor)); 17 18 using namespace sdbusplus::server::xyz::openbmc_project::control; 19 20 // For accessing Host command manager 21 using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>; 22 extern cmdManagerPtr& ipmid_get_host_cmd_manager(); 23 24 //------------------------------------------------------------------- 25 // Called by Host post response from Get_Message_Flags 26 //------------------------------------------------------------------- 27 ipmi::RspType<uint16_t, // id 28 uint8_t, // type 29 uint24_t, // manuf_id 30 uint32_t, // timestamp 31 uint8_t, // netfun 32 uint8_t, // cmd 33 std::array<uint8_t, 4> // data 34 > 35 ipmiAppReadEventBuffer(ipmi::Context::ptr& ctx) 36 { 37 // require this to be limited to system interface 38 if (ctx->channel != ipmi::channelSystemIface) 39 { 40 return ipmi::responseInvalidCommand(); 41 } 42 43 constexpr uint16_t selOemId = 0x5555; 44 constexpr uint8_t selRecordTypeOem = 0xc0; 45 46 // read manufacturer ID from dev_id file 47 static uint24_t manufId{}; 48 if (!manufId) 49 { 50 const char* filename = "/usr/share/ipmi-providers/dev_id.json"; 51 std::ifstream devIdFile(filename); 52 if (devIdFile.is_open()) 53 { 54 auto data = nlohmann::json::parse(devIdFile, nullptr, false); 55 if (!data.is_discarded()) 56 { 57 manufId = data.value("manuf_id", 0); 58 } 59 } 60 } 61 62 constexpr uint32_t timestamp{0}; 63 64 // per IPMI spec NetFuntion for OEM 65 constexpr uint8_t netfun = 0x3a; 66 67 // Read from the Command Manager queue. What gets returned is a 68 // pair of <command, data> that can be directly used here 69 const auto& [cmd, data0] = ipmid_get_host_cmd_manager()->getNextCommand(); 70 constexpr uint8_t dataUnused = 0xff; 71 72 return ipmi::responseSuccess( 73 selOemId, selRecordTypeOem, manufId, timestamp, netfun, cmd, 74 std::to_array<uint8_t>({data0, dataUnused, dataUnused, dataUnused})); 75 } 76 77 //--------------------------------------------------------------------- 78 // Called by Host on seeing a SMS_ATN bit set. Return a hardcoded 79 // value of 0x0 to indicate Event Message Buffer is not supported 80 //------------------------------------------------------------------- 81 ipmi::RspType<uint8_t> ipmiAppGetMessageFlags() 82 { 83 // From IPMI spec V2.0 for Get Message Flags Command : 84 // bit:[1] from LSB : 1b = Event Message Buffer Full. 85 // Return as 0 if Event Message Buffer is not supported, 86 // or when the Event Message buffer is disabled. 87 // This path is used to communicate messages to the host 88 // from within the phosphor::host::command::Manager 89 constexpr uint8_t setEventMsgBufferNotSupported = 0x0; 90 return ipmi::responseSuccess(setEventMsgBufferNotSupported); 91 } 92 93 ipmi::RspType<bool, // Receive Message Queue Interrupt Enabled 94 bool, // Event Message Buffer Full Interrupt Enabled 95 bool, // Event Message Buffer Enabled 96 bool, // System Event Logging Enabled 97 uint1_t, // Reserved 98 bool, // OEM 0 enabled 99 bool, // OEM 1 enabled 100 bool // OEM 2 enabled 101 > 102 ipmiAppGetBMCGlobalEnable() 103 { 104 return ipmi::responseSuccess(true, false, false, true, 0, false, false, 105 false); 106 } 107 108 ipmi::RspType<> ipmiAppSetBMCGlobalEnable( 109 ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled, 110 bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled, 111 bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled, 112 bool OEM1Enabled, bool OEM2Enabled) 113 { 114 ipmi::ChannelInfo chInfo; 115 116 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess) 117 { 118 lg2::error("Failed to get Channel Info, channel={CHANNEL}", "CHANNEL", 119 ctx->channel); 120 return ipmi::responseUnspecifiedError(); 121 } 122 123 if (chInfo.mediumType != 124 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 125 { 126 lg2::error("Error - supported only in system interface"); 127 return ipmi::responseCommandNotAvailable(); 128 } 129 130 // Recv Message Queue and SEL are enabled by default. 131 // Event Message buffer are disabled by default (not supported). 132 // Any request that try to change the mask will be rejected 133 if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable || 134 eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled || 135 OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved) 136 { 137 return ipmi::responseInvalidFieldRequest(); 138 } 139 140 return ipmi::responseSuccess(); 141 } 142 143 namespace 144 { 145 // Static storage to keep the object alive during process life 146 std::unique_ptr<phosphor::host::command::Host> host 147 __attribute__((init_priority(101))); 148 std::unique_ptr<sdbusplus::server::manager_t> objManager 149 __attribute__((init_priority(101))); 150 } // namespace 151 152 void register_netfn_app_functions() 153 { 154 // <Read Event Message Buffer> 155 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 156 ipmi::app::cmdReadEventMessageBuffer, 157 ipmi::Privilege::Admin, ipmiAppReadEventBuffer); 158 159 // <Set BMC Global Enables> 160 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 161 ipmi::app::cmdSetBmcGlobalEnables, 162 ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable); 163 164 // <Get BMC Global Enables> 165 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 166 ipmi::app::cmdGetBmcGlobalEnables, 167 ipmi::Privilege::User, ipmiAppGetBMCGlobalEnable); 168 169 // <Get Message Flags> 170 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 171 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin, 172 ipmiAppGetMessageFlags); 173 174 // Create new xyz.openbmc_project.host object on the bus 175 auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0'; 176 177 std::unique_ptr<sdbusplus::asio::connection>& sdbusp = 178 ipmid_get_sdbus_plus_handler(); 179 180 // Add sdbusplus ObjectManager. 181 objManager = std::make_unique<sdbusplus::server::manager_t>( 182 *sdbusp, CONTROL_HOST_OBJ_MGR); 183 184 host = std::make_unique<phosphor::host::command::Host>(*sdbusp, 185 objPath.c_str()); 186 sdbusp->request_name(CONTROL_HOST_BUSNAME); 187 188 return; 189 } 190