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.hpp" 10 #include "utils.hpp" 11 12 #include <phosphor-logging/log.hpp> 13 #include <phosphor-logging/elog-errors.hpp> 14 #include "xyz/openbmc_project/Common/error.hpp" 15 16 #define SYSTEMD_NETWORKD_DBUS 1 17 18 #ifdef SYSTEMD_NETWORKD_DBUS 19 #include <systemd/sd-bus.h> 20 #include <mapper.h> 21 #endif 22 23 // OpenBMC System Manager dbus framework 24 const char *obj = "/org/openbmc/NetworkManager/Interface"; 25 const char *ifc = "org.openbmc.NetworkManager"; 26 27 const char *nwinterface = "eth0"; 28 29 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx 30 31 struct ChannelConfig_t channelConfig; 32 33 const uint8_t SET_COMPLETE = 0; 34 const uint8_t SET_IN_PROGRESS = 1; 35 const uint8_t SET_COMMIT_WRITE = 2; //Optional 36 const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved 37 38 // Status of Set-In-Progress Parameter (# 0) 39 uint8_t lan_set_in_progress = SET_COMPLETE; 40 41 using namespace phosphor::logging; 42 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 43 44 void register_netfn_transport_functions() __attribute__((constructor)); 45 46 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or 47 // Cache based on Set-In-Progress State 48 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data) 49 { 50 ipmi_ret_t rc = IPMI_CC_OK; 51 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 52 53 try 54 { 55 switch (lan_param) 56 { 57 case LAN_PARM_IP: 58 { 59 std::string ipaddress; 60 if (lan_set_in_progress == SET_COMPLETE) 61 { 62 auto ipObjectInfo = ipmi::getDbusObject( 63 bus, 64 ipmi::network::IP_INTERFACE, 65 ipmi::network::ROOT, 66 ipmi::network::IP_TYPE); 67 68 auto properties = ipmi::getAllDbusProperties( 69 bus, 70 ipObjectInfo.second, 71 ipObjectInfo.first, 72 ipmi::network::IP_INTERFACE); 73 74 ipaddress = properties["Address"].get<std::string>(); 75 } 76 else if (lan_set_in_progress == SET_IN_PROGRESS) 77 { 78 ipaddress = channelConfig.ipaddr; 79 } 80 81 inet_pton(AF_INET, ipaddress.c_str(), 82 reinterpret_cast<void*>(data)); 83 } 84 break; 85 86 case LAN_PARM_SUBNET: 87 { 88 if (lan_set_in_progress == SET_COMPLETE) 89 { 90 auto ipObjectInfo = ipmi::getDbusObject( 91 bus, 92 ipmi::network::IP_INTERFACE, 93 ipmi::network::ROOT, 94 ipmi::network::IP_TYPE); 95 96 auto properties = ipmi::getAllDbusProperties( 97 bus, 98 ipObjectInfo.second, 99 ipObjectInfo.first, 100 ipmi::network::IP_INTERFACE); 101 102 auto prefix = properties["PrefixLength"].get<uint8_t>(); 103 unsigned long mask = ipmi::network::MASK_32_BIT; 104 mask = htonl(mask << (ipmi::network::BITS_32 - prefix)); 105 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE); 106 } 107 else if (lan_set_in_progress == SET_IN_PROGRESS) 108 { 109 inet_pton(AF_INET, channelConfig.netmask.c_str(), 110 reinterpret_cast<void*>(data)); 111 112 } 113 114 } 115 break; 116 117 case LAN_PARM_GATEWAY: 118 { 119 std::string gateway; 120 121 if (lan_set_in_progress == SET_COMPLETE) 122 { 123 auto systemObject = ipmi::getDbusObject( 124 bus, 125 ipmi::network::SYSTEMCONFIG_INTERFACE, 126 ipmi::network::ROOT); 127 128 auto systemProperties = ipmi::getAllDbusProperties( 129 bus, 130 systemObject.second, 131 systemObject.first, 132 ipmi::network::SYSTEMCONFIG_INTERFACE); 133 134 gateway = systemProperties["DefaultGateway"].get< 135 std::string>(); 136 137 } 138 else if (lan_set_in_progress == SET_IN_PROGRESS) 139 { 140 gateway = channelConfig.gateway; 141 } 142 143 inet_pton(AF_INET, gateway.c_str(), 144 reinterpret_cast<void*>(data)); 145 146 } 147 break; 148 149 case LAN_PARM_MAC: 150 { 151 std::string macAddress; 152 if (lan_set_in_progress == SET_COMPLETE) 153 { 154 auto macObjectInfo = ipmi::getDbusObject( 155 bus, 156 ipmi::network::MAC_INTERFACE, 157 ipmi::network::ROOT); 158 159 auto variant = ipmi::getDbusProperty( 160 bus, 161 macObjectInfo.second, 162 macObjectInfo.first, 163 ipmi::network::MAC_INTERFACE, 164 "MACAddress"); 165 166 macAddress = variant.get<std::string>(); 167 168 } 169 else if (lan_set_in_progress == SET_IN_PROGRESS) 170 { 171 macAddress = channelConfig.macAddress; 172 } 173 174 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 175 (data), 176 (data + 1), 177 (data + 2), 178 (data + 3), 179 (data + 4), 180 (data + 5)); 181 } 182 break; 183 184 case LAN_PARM_VLAN: 185 { 186 if (lan_set_in_progress == SET_COMPLETE) 187 { 188 auto ipObjectInfo = ipmi::getDbusObject( 189 bus, 190 ipmi::network::IP_INTERFACE, 191 ipmi::network::ROOT, 192 ipmi::network::IP_TYPE); 193 194 auto vlanID = static_cast<uint16_t>( 195 ipmi::network::getVLAN(ipObjectInfo.first)); 196 197 vlanID = htole16(vlanID); 198 199 if (vlanID) 200 { 201 //Enable the 16th bit 202 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK); 203 } 204 205 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE); 206 } 207 else if (lan_set_in_progress == SET_IN_PROGRESS) 208 { 209 memcpy(data, &(channelConfig.vlanID), 210 ipmi::network::VLAN_SIZE_BYTE); 211 } 212 } 213 break; 214 215 default: 216 rc = IPMI_CC_PARM_OUT_OF_RANGE; 217 } 218 } 219 catch (InternalFailure& e) 220 { 221 commit<InternalFailure>(); 222 rc = IPMI_CC_UNSPECIFIED_ERROR; 223 return rc; 224 } 225 return rc; 226 } 227 228 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 229 ipmi_request_t request, ipmi_response_t response, 230 ipmi_data_len_t data_len, ipmi_context_t context) 231 { 232 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd); 233 // Status code. 234 ipmi_ret_t rc = IPMI_CC_INVALID; 235 *data_len = 0; 236 return rc; 237 } 238 239 struct set_lan_t 240 { 241 uint8_t channel; 242 uint8_t parameter; 243 uint8_t data[8]; // Per IPMI spec, not expecting more than this size 244 } __attribute__((packed)); 245 246 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, 247 ipmi_cmd_t cmd, 248 ipmi_request_t request, 249 ipmi_response_t response, 250 ipmi_data_len_t data_len, 251 ipmi_context_t context) 252 { 253 ipmi_ret_t rc = IPMI_CC_OK; 254 *data_len = 0; 255 256 char ipaddr[INET_ADDRSTRLEN]; 257 char netmask[INET_ADDRSTRLEN]; 258 char gateway[INET_ADDRSTRLEN]; 259 260 auto reqptr = reinterpret_cast<const set_lan_t*>(request); 261 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 262 263 switch (reqptr->parameter) 264 { 265 case LAN_PARM_IP: 266 { 267 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 268 reqptr->data[0], reqptr->data[1], 269 reqptr->data[2], reqptr->data[3]); 270 271 channelConfig.ipaddr.assign(ipaddr); 272 273 } 274 break; 275 276 case LAN_PARM_MAC: 277 { 278 char mac[SIZE_MAC]; 279 280 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 281 reqptr->data[0], 282 reqptr->data[1], 283 reqptr->data[2], 284 reqptr->data[3], 285 reqptr->data[4], 286 reqptr->data[5]); 287 288 auto macObjectInfo = ipmi::getDbusObject( 289 bus, 290 ipmi::network::MAC_INTERFACE, 291 ipmi::network::ROOT, 292 ipmi::network::INTERFACE); 293 294 ipmi::setDbusProperty(bus, 295 macObjectInfo.second, 296 macObjectInfo.first, 297 ipmi::network::MAC_INTERFACE, 298 "MACAddress", 299 std::string(mac)); 300 301 channelConfig.macAddress = mac; 302 303 } 304 break; 305 306 case LAN_PARM_SUBNET: 307 { 308 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 309 reqptr->data[0], reqptr->data[1], 310 reqptr->data[2], reqptr->data[3]); 311 channelConfig.netmask.assign(netmask); 312 } 313 break; 314 315 case LAN_PARM_GATEWAY: 316 { 317 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 318 reqptr->data[0], reqptr->data[1], 319 reqptr->data[2], reqptr->data[3]); 320 channelConfig.gateway.assign(gateway); 321 322 } 323 break; 324 325 case LAN_PARM_VLAN: 326 { 327 uint16_t vlan {}; 328 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); 329 // We are not storing the enable bit 330 // We assume that ipmitool always send enable 331 // bit as 1. 332 vlan = le16toh(vlan); 333 channelConfig.vlanID = vlan; 334 } 335 break; 336 337 case LAN_PARM_INPROGRESS: 338 { 339 if (reqptr->data[0] == SET_COMPLETE) 340 { 341 lan_set_in_progress = SET_COMPLETE; 342 343 log<level::INFO>("Network data from Cache", 344 entry("PREFIX=%s", channelConfig.netmask.c_str()), 345 entry("ADDRESS=%s", channelConfig.ipaddr.c_str()), 346 entry("GATEWAY=%s", channelConfig.gateway.c_str()), 347 entry("VLAN=%d", channelConfig.vlanID)); 348 349 log<level::INFO>("Use Set Channel Access command to apply"); 350 351 } 352 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress 353 { 354 lan_set_in_progress = SET_IN_PROGRESS; 355 } 356 357 } 358 break; 359 360 default: 361 { 362 rc = IPMI_CC_PARM_NOT_SUPPORTED; 363 } 364 365 } 366 367 return rc; 368 } 369 370 struct get_lan_t 371 { 372 uint8_t rev_channel; 373 uint8_t parameter; 374 uint8_t parameter_set; 375 uint8_t parameter_block; 376 } __attribute__((packed)); 377 378 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, 379 ipmi_cmd_t cmd, 380 ipmi_request_t request, 381 ipmi_response_t response, 382 ipmi_data_len_t data_len, 383 ipmi_context_t context) 384 { 385 ipmi_ret_t rc = IPMI_CC_OK; 386 *data_len = 0; 387 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 388 389 get_lan_t *reqptr = (get_lan_t*) request; 390 391 if (reqptr->rev_channel & 0x80) // Revision is bit 7 392 { 393 // Only current revision was requested 394 *data_len = sizeof(current_revision); 395 memcpy(response, ¤t_revision, *data_len); 396 return IPMI_CC_OK; 397 } 398 399 if (reqptr->parameter == LAN_PARM_INPROGRESS) 400 { 401 uint8_t buf[] = {current_revision, lan_set_in_progress}; 402 *data_len = sizeof(buf); 403 memcpy(response, &buf, *data_len); 404 } 405 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT) 406 { 407 uint8_t buf[] = {current_revision,0x04}; 408 *data_len = sizeof(buf); 409 memcpy(response, &buf, *data_len); 410 } 411 else if (reqptr->parameter == LAN_PARM_AUTHENABLES) 412 { 413 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04}; 414 *data_len = sizeof(buf); 415 memcpy(response, &buf, *data_len); 416 } 417 else if ((reqptr->parameter == LAN_PARM_IP) || 418 (reqptr->parameter == LAN_PARM_SUBNET) || 419 (reqptr->parameter == LAN_PARM_GATEWAY) || 420 (reqptr->parameter == LAN_PARM_MAC)) 421 { 422 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1]; 423 424 *data_len = sizeof(current_revision); 425 memcpy(buf, ¤t_revision, *data_len); 426 427 if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK) 428 { 429 if (reqptr->parameter == LAN_PARM_MAC) 430 { 431 *data_len = sizeof(buf); 432 } 433 else 434 { 435 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1; 436 } 437 memcpy(response, &buf, *data_len); 438 } 439 else 440 { 441 rc = IPMI_CC_UNSPECIFIED_ERROR; 442 } 443 } 444 else if (reqptr->parameter == LAN_PARM_VLAN) 445 { 446 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1]; 447 448 *data_len = sizeof(current_revision); 449 memcpy(buf, ¤t_revision, *data_len); 450 if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK) 451 { 452 *data_len = sizeof(buf); 453 memcpy(response, &buf, *data_len); 454 } 455 } 456 else 457 { 458 log<level::ERR>("Unsupported parameter", 459 entry("PARAMETER=0x%x", reqptr->parameter)); 460 rc = IPMI_CC_PARM_NOT_SUPPORTED; 461 } 462 463 return rc; 464 } 465 466 void register_netfn_transport_functions() 467 { 468 // <Wildcard Command> 469 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD); 470 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard, 471 PRIVILEGE_USER); 472 473 // <Set LAN Configuration Parameters> 474 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN); 475 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan, 476 PRIVILEGE_ADMIN); 477 478 // <Get LAN Configuration Parameters> 479 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN); 480 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan, 481 PRIVILEGE_OPERATOR); 482 483 return; 484 } 485