1 #include <cstdio>
2 #include <string>
3 #include <arpa/inet.h>
4 #include <systemd/sd-bus.h>
5 #include <mapper.h>
6 #include <chrono>
7 #include "storagehandler.h"
8 #include "storageaddsel.h"
9 #include "host-ipmid/ipmid-api.h"
10 
11 void register_netfn_storage_functions() __attribute__((constructor));
12 
13 
14 unsigned int   g_sel_time    = 0xFFFFFFFF;
15 extern unsigned short g_sel_reserve;
16 
17 constexpr auto time_manager_intf = "org.openbmc.TimeManager";
18 constexpr auto time_manager_obj = "/org/openbmc/TimeManager";
19 
20 ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
21                               ipmi_request_t request, ipmi_response_t response,
22                               ipmi_data_len_t data_len, ipmi_context_t context)
23 {
24     printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
25     // Status code.
26     ipmi_ret_t rc = IPMI_CC_INVALID;
27     *data_len = 0;
28     return rc;
29 }
30 
31 ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
32                               ipmi_request_t request, ipmi_response_t response,
33                               ipmi_data_len_t data_len, ipmi_context_t context)
34 {
35     using namespace std::chrono;
36 
37     char *time_provider = nullptr;
38     const char* time_in_str = nullptr;
39     uint64_t host_time_usec = 0;
40     uint32_t resp = 0;
41     ipmi_ret_t rc = IPMI_CC_OK;
42 
43     sd_bus_message *reply = nullptr;
44     sd_bus_error bus_error = SD_BUS_ERROR_NULL;
45 
46     printf("IPMI Handling GET-SEL-TIME\n");
47 
48     auto bus = ipmid_get_sd_bus_connection();
49 
50     auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
51     if (rct < 0) {
52         printf("Error [%s] getting bus name for time provider\n",
53             strerror(-rct));
54         rc = IPMI_CC_UNSPECIFIED_ERROR;
55         goto finish;
56     }
57 
58     rct = sd_bus_call_method(bus,
59                     time_provider,
60                     time_manager_obj,
61                     time_manager_intf,
62                     "GetTime",
63                     &bus_error,
64                     &reply,
65                     "s",
66                     "host");
67     if (rct < 0) {
68         printf("Error [%s] getting time\n", strerror(-rct));
69         rc = IPMI_CC_UNSPECIFIED_ERROR;
70         goto finish;
71     }
72 
73     rct = sd_bus_message_read(reply, "sx", &time_in_str, &host_time_usec);
74     if (rct < 0) {
75         fprintf(stderr, "Error [%s] parsing get-time response\n",
76                 strerror(-rct));
77         rc = IPMI_CC_UNSPECIFIED_ERROR;
78         goto finish;
79     }
80 
81     // Time is really long int but IPMI wants just uint32. This works okay until
82     // the number of seconds since 1970 overflows uint32 size.. Still a whole
83     // lot of time here to even think about that.
84     resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
85     resp = htole32(resp);
86     printf("Host Time read:[%s] :: [%d]\n", time_in_str, resp);
87 
88     // From the IPMI Spec 2.0, response should be a 32-bit value
89     *data_len = sizeof(resp);
90 
91     // Pack the actual response
92     memcpy(response, &resp, *data_len);
93 
94 finish:
95     sd_bus_error_free(&bus_error);
96     reply = sd_bus_message_unref(reply);
97     free(time_provider);
98     return rc;
99 }
100 
101 ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
102                               ipmi_request_t request, ipmi_response_t response,
103                               ipmi_data_len_t data_len, ipmi_context_t context)
104 {
105     char *time_provider = nullptr;
106     int time_rc = 0;
107     ipmi_ret_t rc = IPMI_CC_OK;
108 
109     sd_bus_message *reply = nullptr;
110     sd_bus_error bus_error = SD_BUS_ERROR_NULL;
111 
112     uint32_t* secs = (uint32_t*)request;
113     *data_len = 0;
114 
115     printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
116     printf("Data: 0x%X]\n",*secs);
117 
118     auto bus = ipmid_get_sd_bus_connection();
119 
120     auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
121     if (rct < 0) {
122         printf("Error [%s] getting bus name for time provider\n",
123             strerror(-rct));
124         rc = IPMI_CC_UNSPECIFIED_ERROR;
125         goto finish;
126     }
127 
128     rct = sd_bus_call_method(bus,
129             time_provider,
130             time_manager_obj,
131             time_manager_intf,
132             "SetTime",
133             &bus_error,
134             &reply,
135             "ss",
136             "host",
137             std::to_string(le32toh(*secs)).c_str());
138 
139     if (rct < 0) {
140         printf("Error [%s] setting time\n", strerror(-rct));
141         rc = IPMI_CC_UNSPECIFIED_ERROR;
142         goto finish;
143     }
144 
145     rct = sd_bus_message_read(reply, "i", &time_rc);
146     if (rct < 0) {
147         fprintf(stderr, "Error [%s] parsing set-time response\n",
148                 strerror(-rct));
149         rc = IPMI_CC_UNSPECIFIED_ERROR;
150         goto finish;
151     }
152 
153     if (time_rc < 0) {
154         printf("Error setting time.");
155         rc = IPMI_CC_UNSPECIFIED_ERROR;
156     }
157 
158 finish:
159     sd_bus_error_free(&bus_error);
160     reply = sd_bus_message_unref(reply);
161     free(time_provider);
162     return rc;
163 }
164 
165 ipmi_ret_t ipmi_storage_get_sel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
166                               ipmi_request_t request, ipmi_response_t response,
167                               ipmi_data_len_t data_len, ipmi_context_t context)
168 {
169 
170     ipmi_ret_t rc = IPMI_CC_OK;
171     unsigned char buf[] = {0x51,0,0,0xff, 0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0x06};
172 
173     printf("IPMI Handling GET-SEL-INFO\n");
174 
175     *data_len = sizeof(buf);
176 
177     // TODO There is plently of work here.  The SEL DB needs to hold a bunch
178     // of things in a header.  Items like Time Stamp, number of entries, etc
179     // This is one place where the dbus object with the SEL information could
180     // mimic what IPMI needs.
181 
182     // Pack the actual response
183     memcpy(response, &buf, *data_len);
184 
185     return rc;
186 }
187 
188 ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
189                               ipmi_request_t request, ipmi_response_t response,
190                               ipmi_data_len_t data_len, ipmi_context_t context)
191 {
192     ipmi_ret_t rc = IPMI_CC_OK;
193 
194     // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
195     if( ++g_sel_reserve == 0)
196         g_sel_reserve = 1;
197 
198     printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
199 
200     *data_len = sizeof(g_sel_reserve);
201 
202     // Pack the actual response
203     memcpy(response, &g_sel_reserve, *data_len);
204 
205     return rc;
206 }
207 
208 ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
209                               ipmi_request_t request, ipmi_response_t response,
210                               ipmi_data_len_t data_len, ipmi_context_t context)
211 {
212 
213     ipmi_ret_t rc = IPMI_CC_OK;
214     ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
215     uint16_t recordid;
216 
217     recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
218 
219     printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
220 
221     *data_len = sizeof(g_sel_reserve);
222 
223     // Pack the actual response
224     memcpy(response, &p->eventdata[1], 2);
225 
226     send_esel(recordid);
227 
228     return rc;
229 }
230 
231 
232 
233 void register_netfn_storage_functions()
234 {
235     // <Wildcard Command>
236     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
237     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
238                            PRIVILEGE_USER);
239 
240     // <Get SEL Time>
241     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
242     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
243                            PRIVILEGE_USER);
244 
245     // <Set SEL Time>
246     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
247     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
248                            PRIVILEGE_OPERATOR);
249 
250     // <Get SEL Info>
251     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
252     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, ipmi_storage_get_sel_info,
253                            PRIVILEGE_USER);
254 
255     // <Reserve SEL>
256     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
257     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
258                            PRIVILEGE_USER);
259 
260     // <Add SEL Entry>
261     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
262     ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
263                            PRIVILEGE_OPERATOR);
264     return;
265 }
266 
267