1 #include "config.h"
2 
3 #include "systemintfcmds.hpp"
4 
5 #include "host-cmd-manager.hpp"
6 #include "host-interface.hpp"
7 
8 #include <cstring>
9 #include <ipmid-host/cmd.hpp>
10 #include <ipmid/api.hpp>
11 #include <ipmid/registration.hpp>
12 
13 void register_netfn_app_functions() __attribute__((constructor));
14 
15 using namespace sdbusplus::xyz::openbmc_project::Control::server;
16 
17 // For accessing Host command manager
18 using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
19 extern cmdManagerPtr& ipmid_get_host_cmd_manager();
20 
21 // global enables
22 // bit0   - Message Receive Queue enable
23 // bit1   - Enable Event Message Buffer Full Interrupt
24 // bit2   - Enable Event Message Buffer
25 // bit3   - Enable System Event Logging
26 // bit4   - reserved
27 // bit5-7 - OEM 0~2 enables
28 static constexpr uint8_t selEnable = 0x08;
29 static constexpr uint8_t recvMsgQueueEnable = 0x01;
30 static constexpr uint8_t globalEnablesDefault = selEnable | recvMsgQueueEnable;
31 
32 //-------------------------------------------------------------------
33 // Called by Host post response from Get_Message_Flags
34 //-------------------------------------------------------------------
35 ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
36                                ipmi_request_t request, ipmi_response_t response,
37                                ipmi_data_len_t data_len, ipmi_context_t context)
38 {
39     ipmi_ret_t rc = IPMI_CC_OK;
40 
41     struct oem_sel_timestamped oem_sel = {0};
42     *data_len = sizeof(struct oem_sel_timestamped);
43 
44     // either id[0] -or- id[1] can be filled in. We will use id[0]
45     oem_sel.id[0] = SEL_OEM_ID_0;
46     oem_sel.id[1] = SEL_OEM_ID_0;
47     oem_sel.type = SEL_RECORD_TYPE_OEM;
48 
49     // Following 3 bytes are from IANA Manufactre_Id field. See below
50     oem_sel.manuf_id[0] = 0x41;
51     oem_sel.manuf_id[1] = 0xA7;
52     oem_sel.manuf_id[2] = 0x00;
53 
54     // per IPMI spec NetFuntion for OEM
55     oem_sel.netfun = 0x3A;
56 
57     // Read from the Command Manager queue. What gets returned is a
58     // pair of <command, data> that can be directly used here
59     auto hostCmd = ipmid_get_host_cmd_manager()->getNextCommand();
60     oem_sel.cmd = hostCmd.first;
61     oem_sel.data[0] = hostCmd.second;
62 
63     // All '0xFF' since unused.
64     std::memset(&oem_sel.data[1], 0xFF, 3);
65 
66     // Pack the actual response
67     std::memcpy(response, &oem_sel, *data_len);
68     return rc;
69 }
70 
71 //---------------------------------------------------------------------
72 // Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
73 // value of 0x2 indicating we need Host read some data.
74 //-------------------------------------------------------------------
75 ipmi_ret_t ipmi_app_get_msg_flags(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
76                                   ipmi_request_t request,
77                                   ipmi_response_t response,
78                                   ipmi_data_len_t data_len,
79                                   ipmi_context_t context)
80 {
81     // Generic return from IPMI commands.
82     ipmi_ret_t rc = IPMI_CC_OK;
83 
84     // From IPMI spec V2.0 for Get Message Flags Command :
85     // bit:[1] from LSB : 1b = Event Message Buffer Full.
86     // Return as 0 if Event Message Buffer is not supported,
87     // or when the Event Message buffer is disabled.
88     // For now, it is not supported.
89 
90     uint8_t set_event_msg_buffer_full = 0x0;
91     *data_len = sizeof(set_event_msg_buffer_full);
92 
93     // Pack the actual response
94     std::memcpy(response, &set_event_msg_buffer_full, *data_len);
95 
96     return rc;
97 }
98 
99 ipmi_ret_t ipmi_app_get_bmc_global_enables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
100                                            ipmi_request_t request,
101                                            ipmi_response_t response,
102                                            ipmi_data_len_t data_len,
103                                            ipmi_context_t context)
104 {
105     ipmi_ret_t rc = IPMI_CC_OK;
106     if (0 != *data_len)
107     {
108         *data_len = 0;
109         return IPMI_CC_REQ_DATA_LEN_INVALID;
110     }
111     *data_len = sizeof(globalEnablesDefault);
112     *reinterpret_cast<uint8_t*>(response) = globalEnablesDefault;
113     return rc;
114 }
115 
116 ipmi_ret_t ipmi_app_set_bmc_global_enables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
117                                            ipmi_request_t request,
118                                            ipmi_response_t response,
119                                            ipmi_data_len_t data_len,
120                                            ipmi_context_t context)
121 {
122     ipmi_ret_t rc = IPMI_CC_OK;
123 
124     uint8_t reqMask = *reinterpret_cast<uint8_t*>(request);
125     if (sizeof(reqMask) != *data_len)
126     {
127         *data_len = 0;
128         return IPMI_CC_REQ_DATA_LEN_INVALID;
129     }
130 
131     *data_len = 0;
132     // Recv Message Queue and SEL are enabled by default.
133     // Event Message buffer are disabled by default (not supported).
134     // Any request that try to change the mask will be rejected
135     if (reqMask != (selEnable | recvMsgQueueEnable))
136     {
137         return IPMI_CC_INVALID_FIELD_REQUEST;
138     }
139     return rc;
140 }
141 
142 namespace
143 {
144 // Static storage to keep the object alive during process life
145 std::unique_ptr<phosphor::host::command::Host> host
146     __attribute__((init_priority(101)));
147 std::unique_ptr<sdbusplus::server::manager::manager> objManager
148     __attribute__((init_priority(101)));
149 std::unique_ptr<sdbusplus::asio::connection> sdbusp
150     __attribute__((init_priority(101)));
151 } // namespace
152 
153 // this is used by openpower-host-ipmi-oem
154 std::unique_ptr<sdbusplus::asio::connection>& ipmid_get_sdbus_plus_handler()
155 {
156     return sdbusp;
157 }
158 
159 #include <unistd.h>
160 void register_netfn_app_functions()
161 {
162 
163     // <Read Event Message Buffer>
164     ipmi_register_callback(NETFUN_APP, IPMI_CMD_READ_EVENT, NULL,
165                            ipmi_app_read_event, SYSTEM_INTERFACE);
166 
167     // <Set BMC Global Enables>
168     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_BMC_GLOBAL_ENABLES, NULL,
169                            ipmi_app_set_bmc_global_enables, SYSTEM_INTERFACE);
170 
171     // <Get BMC Global Enables>
172     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_BMC_GLOBAL_ENABLES, NULL,
173                            ipmi_app_get_bmc_global_enables, SYSTEM_INTERFACE);
174 
175     // <Get Message Flags>
176     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS, NULL,
177                            ipmi_app_get_msg_flags, SYSTEM_INTERFACE);
178 
179     // Create new xyz.openbmc_project.host object on the bus
180     auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';
181 
182     // Create a new sdbus connection so it can have a well-known name
183     sd_bus* bus = nullptr;
184     sd_bus_open_system(&bus);
185     if (!bus)
186     {
187         return;
188     }
189     auto io = getIoService();
190     sdbusp = std::make_unique<sdbusplus::asio::connection>(*io, bus);
191 
192     // Add sdbusplus ObjectManager.
193     objManager = std::make_unique<sdbusplus::server::manager::manager>(
194         *sdbusp, CONTROL_HOST_OBJ_MGR);
195 
196     host = std::make_unique<phosphor::host::command::Host>(*sdbusp,
197                                                            objPath.c_str());
198     sdbusp->request_name(CONTROL_HOST_BUSNAME);
199 
200     return;
201 }
202