1 #include <stdio.h> 2 #include <string.h> 3 #include <stdint.h> 4 #include <arpa/inet.h> 5 #include <string> 6 7 #include "host-ipmid/ipmid-api.h" 8 #include "ipmid.hpp" 9 #include "transporthandler.h" 10 11 #define SYSTEMD_NETWORKD_DBUS 1 12 13 #ifdef SYSTEMD_NETWORKD_DBUS 14 #include <systemd/sd-bus.h> 15 #include <mapper.h> 16 #endif 17 18 // OpenBMC System Manager dbus framework 19 const char *obj = "/org/openbmc/NetworkManager/Interface"; 20 const char *ifc = "org.openbmc.NetworkManager"; 21 22 const char *nwinterface = "eth0"; 23 24 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx 25 26 struct channel_config_t channel_config; 27 28 const uint8_t SET_COMPLETE = 0; 29 const uint8_t SET_IN_PROGRESS = 1; 30 const uint8_t SET_COMMIT_WRITE = 2; //Optional 31 const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved 32 33 // Status of Set-In-Progress Parameter (# 0) 34 uint8_t lan_set_in_progress = SET_COMPLETE; 35 36 37 38 void register_netfn_transport_functions() __attribute__((constructor)); 39 40 // Helper Function to get IP Address/NetMask/Gateway from Network Manager or 41 // Cache based on Set-In-Progress State 42 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t * data) 43 { 44 sd_bus *bus = ipmid_get_sd_bus_connection(); 45 sd_bus_message *reply = NULL; 46 sd_bus_error error = SD_BUS_ERROR_NULL; 47 int family; 48 unsigned char prefixlen; 49 char* ipaddr = NULL; 50 unsigned long mask = 0xFFFFFFFF; 51 char* gateway = NULL; 52 int r = 0; 53 ipmi_ret_t rc = IPMI_CC_OK; 54 char *app = NULL; 55 56 r = mapper_get_service(bus, obj, &app); 57 if (r < 0) { 58 fprintf(stderr, "Failed to get %s bus name: %s\n", 59 obj, strerror(-r)); 60 rc = IPMI_CC_UNSPECIFIED_ERROR; 61 goto cleanup; 62 } 63 r = sd_bus_call_method(bus, app, obj, ifc, "GetAddress4", &error, 64 &reply, "s", nwinterface); 65 if(r < 0) 66 { 67 fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r)); 68 rc = IPMI_CC_UNSPECIFIED_ERROR; 69 goto cleanup; 70 } 71 72 r = sd_bus_message_read(reply, "iyss", 73 &family, &prefixlen, &ipaddr, &gateway); 74 if(r < 0) 75 { 76 fprintf(stderr, "Failed to get a response: %s\n", strerror(-rc)); 77 rc = IPMI_CC_RESPONSE_ERROR; 78 goto cleanup; 79 } 80 81 printf("N/W data from HW %s:%d:%s:%s\n", 82 family==AF_INET?"IPv4":"IPv6", prefixlen, ipaddr,gateway); 83 printf("N/W data from Cache: %s:%s:%s\n", 84 channel_config.new_ipaddr.c_str(), 85 channel_config.new_netmask.c_str(), 86 channel_config.new_gateway.c_str()); 87 88 if(lan_param == LAN_PARM_IP) 89 { 90 if(lan_set_in_progress == SET_COMPLETE) 91 { 92 std::string ipaddrstr(ipaddr); 93 inet_pton(AF_INET, ipaddrstr.c_str(),(void *)data); 94 } 95 else if(lan_set_in_progress == SET_IN_PROGRESS) 96 { 97 inet_pton(AF_INET, channel_config.new_ipaddr.c_str(), (void *)data); 98 } 99 } 100 else if(lan_param == LAN_PARM_SUBNET) 101 { 102 if(lan_set_in_progress == SET_COMPLETE) 103 { 104 mask = htonl(mask<<(32-prefixlen)); 105 memcpy(data, &mask, 4); 106 } 107 else if(lan_set_in_progress == SET_IN_PROGRESS) 108 { 109 inet_pton(AF_INET, channel_config.new_netmask.c_str(), (void *)data); 110 } 111 } 112 else if(lan_param == LAN_PARM_GATEWAY) 113 { 114 if(lan_set_in_progress == SET_COMPLETE) 115 { 116 std::string gatewaystr(gateway); 117 inet_pton(AF_INET, gatewaystr.c_str(), (void *)data); 118 } 119 else if(lan_set_in_progress == SET_IN_PROGRESS) 120 { 121 inet_pton(AF_INET, channel_config.new_gateway.c_str(),(void *)data); 122 } 123 } 124 else 125 { 126 rc = IPMI_CC_PARM_OUT_OF_RANGE; 127 } 128 129 cleanup: 130 sd_bus_error_free(&error); 131 reply = sd_bus_message_unref(reply); 132 free(app); 133 134 return rc; 135 } 136 137 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 138 ipmi_request_t request, ipmi_response_t response, 139 ipmi_data_len_t data_len, ipmi_context_t context) 140 { 141 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd); 142 // Status code. 143 ipmi_ret_t rc = IPMI_CC_INVALID; 144 *data_len = 0; 145 return rc; 146 } 147 148 struct set_lan_t { 149 uint8_t channel; 150 uint8_t parameter; 151 uint8_t data[8]; // Per IPMI spec, not expecting more than this size 152 } __attribute__ ((packed)); 153 154 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 155 ipmi_request_t request, ipmi_response_t response, 156 ipmi_data_len_t data_len, ipmi_context_t context) 157 { 158 ipmi_ret_t rc = IPMI_CC_OK; 159 *data_len = 0; 160 sd_bus *bus = ipmid_get_sd_bus_connection(); 161 sd_bus_message *reply = nullptr; 162 sd_bus_error error = SD_BUS_ERROR_NULL; 163 int r = 0; 164 char *app = nullptr; 165 166 char tmp_ipaddr[INET_ADDRSTRLEN]; 167 char tmp_netmask[INET_ADDRSTRLEN]; 168 char tmp_gateway[INET_ADDRSTRLEN]; 169 170 printf("IPMI SET_LAN\n"); 171 172 set_lan_t *reqptr = (set_lan_t*) request; 173 174 if (reqptr->parameter == LAN_PARM_IP) { 175 snprintf(tmp_ipaddr, INET_ADDRSTRLEN, "%d.%d.%d.%d", 176 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]); 177 channel_config.new_ipaddr.assign(tmp_ipaddr); 178 } else if (reqptr->parameter == LAN_PARM_MAC) { 179 char mac[SIZE_MAC]; 180 181 snprintf(mac, SIZE_MAC, "%02x:%02x:%02x:%02x:%02x:%02x", 182 reqptr->data[0], 183 reqptr->data[1], 184 reqptr->data[2], 185 reqptr->data[3], 186 reqptr->data[4], 187 reqptr->data[5]); 188 189 r = mapper_get_service(bus, obj, &app); 190 if (r < 0) { 191 fprintf(stderr, "Failed to get %s bus name: %s\n", 192 obj, strerror(-r)); 193 goto finish; 194 } 195 r = sd_bus_call_method(bus, app, obj, ifc, "SetHwAddress", &error, 196 &reply, "ss", nwinterface, mac); 197 if (r < 0) { 198 fprintf(stderr, "Failed to call the method: %s\n", strerror(-r)); 199 rc = IPMI_CC_UNSPECIFIED_ERROR; 200 } 201 } else if (reqptr->parameter == LAN_PARM_SUBNET) 202 { 203 snprintf(tmp_netmask, INET_ADDRSTRLEN, "%d.%d.%d.%d", 204 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]); 205 channel_config.new_netmask.assign(tmp_netmask); 206 } else if (reqptr->parameter == LAN_PARM_GATEWAY) 207 { 208 snprintf(tmp_gateway, INET_ADDRSTRLEN, "%d.%d.%d.%d", 209 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]); 210 channel_config.new_gateway.assign(tmp_gateway); 211 } else if (reqptr->parameter == LAN_PARM_INPROGRESS) 212 { 213 if(reqptr->data[0] == SET_COMPLETE) { 214 lan_set_in_progress = SET_COMPLETE; 215 216 printf("N/W data from Cache: %s:%s:%s\n", 217 channel_config.new_ipaddr.c_str(), 218 channel_config.new_netmask.c_str(), 219 channel_config.new_gateway.c_str()); 220 printf("Use Set Channel Access command to apply them\n"); 221 222 } else if(reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress 223 { 224 lan_set_in_progress = SET_IN_PROGRESS; 225 } 226 } else 227 { 228 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter); 229 rc = IPMI_CC_PARM_NOT_SUPPORTED; 230 } 231 232 finish: 233 sd_bus_error_free(&error); 234 reply = sd_bus_message_unref(reply); 235 free(app); 236 237 return rc; 238 } 239 240 struct get_lan_t { 241 uint8_t rev_channel; 242 uint8_t parameter; 243 uint8_t parameter_set; 244 uint8_t parameter_block; 245 } __attribute__ ((packed)); 246 247 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 248 ipmi_request_t request, ipmi_response_t response, 249 ipmi_data_len_t data_len, ipmi_context_t context) 250 { 251 ipmi_ret_t rc = IPMI_CC_OK; 252 *data_len = 0; 253 sd_bus *bus = ipmid_get_sd_bus_connection(); 254 sd_bus_message *reply = NULL; 255 sd_bus_error error = SD_BUS_ERROR_NULL; 256 int r = 0; 257 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 258 int i = 0; 259 char *app = NULL; 260 261 printf("IPMI GET_LAN\n"); 262 263 get_lan_t *reqptr = (get_lan_t*) request; 264 265 if (reqptr->rev_channel & 0x80) // Revision is bit 7 266 { 267 // Only current revision was requested 268 *data_len = sizeof(current_revision); 269 memcpy(response, ¤t_revision, *data_len); 270 return IPMI_CC_OK; 271 } 272 273 // TODO Use dbus interface once available. For now use ip cmd. 274 // TODO Add the rest of the parameters, like gateway 275 276 if (reqptr->parameter == LAN_PARM_INPROGRESS) 277 { 278 uint8_t buf[] = {current_revision, lan_set_in_progress}; 279 *data_len = sizeof(buf); 280 memcpy(response, &buf, *data_len); 281 } 282 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT) 283 { 284 uint8_t buf[] = {current_revision,0x04}; 285 *data_len = sizeof(buf); 286 memcpy(response, &buf, *data_len); 287 } 288 else if (reqptr->parameter == LAN_PARM_AUTHENABLES) 289 { 290 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04}; 291 *data_len = sizeof(buf); 292 memcpy(response, &buf, *data_len); 293 } 294 else if ((reqptr->parameter == LAN_PARM_IP) || (reqptr->parameter == LAN_PARM_SUBNET) || (reqptr->parameter == LAN_PARM_GATEWAY)) 295 { 296 uint8_t buf[5]; 297 298 *data_len = sizeof(current_revision); 299 memcpy(buf, ¤t_revision, *data_len); 300 301 if(getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK) 302 { 303 *data_len = sizeof(buf); 304 memcpy(response, &buf, *data_len); 305 } 306 else 307 { 308 rc = IPMI_CC_UNSPECIFIED_ERROR; 309 } 310 } 311 else if (reqptr->parameter == LAN_PARM_MAC) 312 { 313 //string to parse: link/ether xx:xx:xx:xx:xx:xx 314 uint8_t buf[7]; 315 char *eaddr1 = NULL; 316 317 r = mapper_get_service(bus, obj, &app); 318 if (r < 0) { 319 fprintf(stderr, "Failed to get %s bus name: %s\n", 320 obj, strerror(-r)); 321 goto cleanup; 322 } 323 r = sd_bus_call_method(bus, app, obj, ifc, "GetHwAddress", &error, 324 &reply, "s", nwinterface); 325 if(r < 0) 326 { 327 fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r)); 328 rc = IPMI_CC_UNSPECIFIED_ERROR; 329 goto cleanup; 330 } 331 332 r = sd_bus_message_read(reply, "s", &eaddr1); 333 if (r < 0) 334 { 335 fprintf(stderr, "Failed to get a response: %s", strerror(-r)); 336 rc = IPMI_CC_UNSPECIFIED_ERROR; 337 goto cleanup; 338 } 339 if (eaddr1 == NULL) 340 { 341 fprintf(stderr, "Failed to get a valid response: %s", strerror(-r)); 342 rc = IPMI_CC_UNSPECIFIED_ERROR; 343 goto cleanup; 344 } 345 346 memcpy((void*)&buf[0], ¤t_revision, 1); 347 348 char *tokptr = NULL; 349 char* digit = strtok_r(eaddr1, ":", &tokptr); 350 if (digit == NULL) 351 { 352 fprintf(stderr, "Unexpected MAC format: %s", eaddr1); 353 rc = IPMI_CC_RESPONSE_ERROR; 354 goto cleanup; 355 } 356 357 i=0; 358 while (digit != NULL) 359 { 360 int resp_byte = strtoul(digit, NULL, 16); 361 memcpy((void*)&buf[i+1], &resp_byte, 1); 362 i++; 363 digit = strtok_r(NULL, ":", &tokptr); 364 } 365 366 *data_len = sizeof(buf); 367 memcpy(response, &buf, *data_len); 368 } 369 else 370 { 371 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter); 372 rc = IPMI_CC_PARM_NOT_SUPPORTED; 373 } 374 375 cleanup: 376 sd_bus_error_free(&error); 377 reply = sd_bus_message_unref(reply); 378 free(app); 379 380 return rc; 381 } 382 383 void register_netfn_transport_functions() 384 { 385 // <Wildcard Command> 386 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD); 387 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard, 388 PRIVILEGE_USER); 389 390 // <Set LAN Configuration Parameters> 391 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN); 392 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan, 393 PRIVILEGE_ADMIN); 394 395 // <Get LAN Configuration Parameters> 396 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN); 397 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan, 398 PRIVILEGE_OPERATOR); 399 400 return; 401 } 402