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