1 #include <stdio.h> 2 #include <string.h> 3 #include <stdint.h> 4 #include <arpa/inet.h> 5 #include <string> 6 #include <experimental/filesystem> 7 8 #include "host-ipmid/ipmid-api.h" 9 #include "ipmid.hpp" 10 #include "transporthandler.hpp" 11 #include "utils.hpp" 12 #include "net.hpp" 13 14 #include <phosphor-logging/log.hpp> 15 #include <phosphor-logging/elog-errors.hpp> 16 #include "xyz/openbmc_project/Common/error.hpp" 17 18 #define SYSTEMD_NETWORKD_DBUS 1 19 20 #ifdef SYSTEMD_NETWORKD_DBUS 21 #include <systemd/sd-bus.h> 22 #include <mapper.h> 23 #endif 24 25 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx 26 27 std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; 28 29 using namespace phosphor::logging; 30 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 31 namespace fs = std::experimental::filesystem; 32 33 void register_netfn_transport_functions() __attribute__((constructor)); 34 35 struct ChannelConfig_t* getChannelConfig(int channel) 36 { 37 auto item = channelConfig.find(channel); 38 if (item == channelConfig.end()) 39 { 40 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>(); 41 } 42 43 return channelConfig[channel].get(); 44 } 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, int channel) 49 { 50 ipmi_ret_t rc = IPMI_CC_OK; 51 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 52 53 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 54 // if ethdevice is an empty string they weren't expecting this channel. 55 if (ethdevice.empty()) 56 { 57 // TODO: return error from getNetworkData() 58 return IPMI_CC_INVALID_FIELD_REQUEST; 59 } 60 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE; 61 auto channelConf = getChannelConfig(channel); 62 63 try 64 { 65 switch (lan_param) 66 { 67 case LAN_PARM_IP: 68 { 69 std::string ipaddress; 70 if (channelConf->lan_set_in_progress == SET_COMPLETE) 71 { 72 try 73 { 74 auto ipObjectInfo = ipmi::getIPObject( 75 bus, 76 ipmi::network::IP_INTERFACE, 77 ipmi::network::ROOT, 78 ethIP); 79 80 auto properties = ipmi::getAllDbusProperties( 81 bus, 82 ipObjectInfo.second, 83 ipObjectInfo.first, 84 ipmi::network::IP_INTERFACE); 85 86 ipaddress = properties["Address"].get<std::string>(); 87 } 88 // ignore the exception, as it is a valid condtion that 89 // system is not confiured with any ip. 90 catch (InternalFailure& e) 91 { 92 // nothing to do. 93 } 94 } 95 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 96 { 97 ipaddress = channelConf->ipaddr; 98 } 99 100 inet_pton(AF_INET, ipaddress.c_str(), 101 reinterpret_cast<void*>(data)); 102 } 103 break; 104 105 case LAN_PARM_IPSRC: 106 { 107 std::string networkInterfacePath; 108 109 if (channelConf->lan_set_in_progress == SET_COMPLETE) 110 { 111 try 112 { 113 ipmi::ObjectTree ancestorMap; 114 // if the system is having ip object,then 115 // get the IP object. 116 auto ipObject = ipmi::getDbusObject( 117 bus, 118 ipmi::network::IP_INTERFACE, 119 ipmi::network::ROOT, 120 ethIP); 121 122 // Get the parent interface of the IP object. 123 try 124 { 125 ipmi::InterfaceList interfaces; 126 interfaces.emplace_back( 127 ipmi::network::ETHERNET_INTERFACE); 128 129 ancestorMap = ipmi::getAllAncestors( 130 bus, 131 ipObject.first, 132 std::move(interfaces)); 133 } 134 catch (InternalFailure& e) 135 { 136 // if unable to get the parent interface 137 // then commit the error and return. 138 log<level::ERR>("Unable to get the parent interface", 139 entry("PATH=%s", ipObject.first.c_str()), 140 entry("INTERFACE=%s", 141 ipmi::network::ETHERNET_INTERFACE)); 142 break; 143 144 } 145 // for an ip object there would be single parent 146 // interface. 147 networkInterfacePath = ancestorMap.begin()->first; 148 } 149 catch (InternalFailure& e) 150 { 151 // if there is no ip configured on the system,then 152 // get the network interface object. 153 auto networkInterfaceObject = ipmi::getDbusObject( 154 bus, 155 ipmi::network::ETHERNET_INTERFACE, 156 ipmi::network::ROOT, 157 ethdevice); 158 159 networkInterfacePath = networkInterfaceObject.first; 160 } 161 162 auto variant = ipmi::getDbusProperty( 163 bus, 164 ipmi::network::SERVICE, 165 networkInterfacePath, 166 ipmi::network::ETHERNET_INTERFACE, 167 "DHCPEnabled"); 168 169 auto dhcpEnabled = variant.get<bool>(); 170 // As per IPMI spec 2=>DHCP, 1=STATIC 171 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP : 172 ipmi::network::IPOrigin::STATIC; 173 174 memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE); 175 } 176 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 177 { 178 memcpy(data, &(channelConf->ipsrc), 179 ipmi::network::IPSRC_SIZE_BYTE); 180 } 181 } 182 break; 183 184 case LAN_PARM_SUBNET: 185 { 186 unsigned long mask {}; 187 if (channelConf->lan_set_in_progress == SET_COMPLETE) 188 { 189 try 190 { 191 auto ipObjectInfo = ipmi::getIPObject( 192 bus, 193 ipmi::network::IP_INTERFACE, 194 ipmi::network::ROOT, 195 ipmi::network::IP_TYPE); 196 197 auto properties = ipmi::getAllDbusProperties( 198 bus, 199 ipObjectInfo.second, 200 ipObjectInfo.first, 201 ipmi::network::IP_INTERFACE); 202 203 auto prefix = properties["PrefixLength"].get<uint8_t>(); 204 mask = ipmi::network::MASK_32_BIT; 205 mask = htonl(mask << (ipmi::network::BITS_32 - prefix)); 206 } 207 // ignore the exception, as it is a valid condtion that 208 // system is not confiured with any ip. 209 catch (InternalFailure& e) 210 { 211 // nothing to do 212 } 213 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE); 214 } 215 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 216 { 217 inet_pton(AF_INET, channelConf->netmask.c_str(), 218 reinterpret_cast<void*>(data)); 219 } 220 221 } 222 break; 223 224 case LAN_PARM_GATEWAY: 225 { 226 std::string gateway; 227 228 if (channelConf->lan_set_in_progress == SET_COMPLETE) 229 { 230 try 231 { 232 auto systemObject = ipmi::getDbusObject( 233 bus, 234 ipmi::network::SYSTEMCONFIG_INTERFACE, 235 ipmi::network::ROOT); 236 237 auto systemProperties = ipmi::getAllDbusProperties( 238 bus, 239 systemObject.second, 240 systemObject.first, 241 ipmi::network::SYSTEMCONFIG_INTERFACE); 242 243 gateway = systemProperties["DefaultGateway"].get< 244 std::string>(); 245 } 246 // ignore the exception, as it is a valid condtion that 247 // system is not confiured with any ip. 248 catch (InternalFailure& e) 249 { 250 // nothing to do 251 } 252 253 } 254 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 255 { 256 gateway = channelConf->gateway; 257 } 258 259 inet_pton(AF_INET, gateway.c_str(), 260 reinterpret_cast<void*>(data)); 261 } 262 break; 263 264 case LAN_PARM_MAC: 265 { 266 std::string macAddress; 267 if (channelConf->lan_set_in_progress == SET_COMPLETE) 268 { 269 auto macObjectInfo = ipmi::getDbusObject( 270 bus, 271 ipmi::network::MAC_INTERFACE, 272 ipmi::network::ROOT, 273 ethdevice); 274 275 auto variant = ipmi::getDbusProperty( 276 bus, 277 macObjectInfo.second, 278 macObjectInfo.first, 279 ipmi::network::MAC_INTERFACE, 280 "MACAddress"); 281 282 macAddress = variant.get<std::string>(); 283 284 } 285 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 286 { 287 macAddress = channelConf->macAddress; 288 } 289 290 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 291 (data), 292 (data + 1), 293 (data + 2), 294 (data + 3), 295 (data + 4), 296 (data + 5)); 297 } 298 break; 299 300 case LAN_PARM_VLAN: 301 { 302 uint16_t vlanID {}; 303 if (channelConf->lan_set_in_progress == SET_COMPLETE) 304 { 305 try 306 { 307 auto ipObjectInfo = ipmi::getIPObject( 308 bus, 309 ipmi::network::IP_INTERFACE, 310 ipmi::network::ROOT, 311 ipmi::network::IP_TYPE); 312 313 vlanID = static_cast<uint16_t>( 314 ipmi::network::getVLAN(ipObjectInfo.first)); 315 316 vlanID = htole16(vlanID); 317 318 if (vlanID) 319 { 320 //Enable the 16th bit 321 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK); 322 } 323 } 324 // ignore the exception, as it is a valid condtion that 325 // system is not confiured with any ip. 326 catch (InternalFailure& e) 327 { 328 // nothing to do 329 } 330 331 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE); 332 } 333 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 334 { 335 memcpy(data, &(channelConf->vlanID), 336 ipmi::network::VLAN_SIZE_BYTE); 337 } 338 } 339 break; 340 341 default: 342 rc = IPMI_CC_PARM_OUT_OF_RANGE; 343 } 344 } 345 catch (InternalFailure& e) 346 { 347 commit<InternalFailure>(); 348 rc = IPMI_CC_UNSPECIFIED_ERROR; 349 return rc; 350 } 351 return rc; 352 } 353 354 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 355 ipmi_request_t request, ipmi_response_t response, 356 ipmi_data_len_t data_len, ipmi_context_t context) 357 { 358 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd); 359 // Status code. 360 ipmi_ret_t rc = IPMI_CC_INVALID; 361 *data_len = 0; 362 return rc; 363 } 364 365 struct set_lan_t 366 { 367 uint8_t channel; 368 uint8_t parameter; 369 uint8_t data[8]; // Per IPMI spec, not expecting more than this size 370 } __attribute__((packed)); 371 372 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, 373 ipmi_cmd_t cmd, 374 ipmi_request_t request, 375 ipmi_response_t response, 376 ipmi_data_len_t data_len, 377 ipmi_context_t context) 378 { 379 ipmi_ret_t rc = IPMI_CC_OK; 380 *data_len = 0; 381 382 char ipaddr[INET_ADDRSTRLEN]; 383 char netmask[INET_ADDRSTRLEN]; 384 char gateway[INET_ADDRSTRLEN]; 385 386 auto reqptr = reinterpret_cast<const set_lan_t*>(request); 387 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 388 389 // channel number is the lower nibble 390 int channel = reqptr->channel & CHANNEL_MASK; 391 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 392 if (ethdevice.empty()) 393 { 394 return IPMI_CC_INVALID_FIELD_REQUEST; 395 } 396 auto channelConf = getChannelConfig(channel); 397 398 switch (reqptr->parameter) 399 { 400 case LAN_PARM_IP: 401 { 402 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 403 reqptr->data[0], reqptr->data[1], 404 reqptr->data[2], reqptr->data[3]); 405 406 channelConf->ipaddr.assign(ipaddr); 407 } 408 break; 409 410 case LAN_PARM_IPSRC: 411 { 412 uint8_t ipsrc{}; 413 memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); 414 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); 415 } 416 break; 417 418 case LAN_PARM_MAC: 419 { 420 char mac[SIZE_MAC]; 421 422 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 423 reqptr->data[0], 424 reqptr->data[1], 425 reqptr->data[2], 426 reqptr->data[3], 427 reqptr->data[4], 428 reqptr->data[5]); 429 430 auto macObjectInfo = ipmi::getDbusObject( 431 bus, 432 ipmi::network::MAC_INTERFACE, 433 ipmi::network::ROOT, 434 ethdevice); 435 436 ipmi::setDbusProperty(bus, 437 macObjectInfo.second, 438 macObjectInfo.first, 439 ipmi::network::MAC_INTERFACE, 440 "MACAddress", 441 std::string(mac)); 442 443 channelConf->macAddress = mac; 444 } 445 break; 446 447 case LAN_PARM_SUBNET: 448 { 449 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 450 reqptr->data[0], reqptr->data[1], 451 reqptr->data[2], reqptr->data[3]); 452 channelConf->netmask.assign(netmask); 453 } 454 break; 455 456 case LAN_PARM_GATEWAY: 457 { 458 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 459 reqptr->data[0], reqptr->data[1], 460 reqptr->data[2], reqptr->data[3]); 461 channelConf->gateway.assign(gateway); 462 } 463 break; 464 465 case LAN_PARM_VLAN: 466 { 467 uint16_t vlan {}; 468 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); 469 // We are not storing the enable bit 470 // We assume that ipmitool always send enable 471 // bit as 1. 472 vlan = le16toh(vlan); 473 channelConf->vlanID = vlan; 474 } 475 break; 476 477 case LAN_PARM_INPROGRESS: 478 { 479 if (reqptr->data[0] == SET_COMPLETE) 480 { 481 channelConf->lan_set_in_progress = SET_COMPLETE; 482 483 log<level::INFO>("Network data from Cache", 484 entry("PREFIX=%s", channelConf->netmask.c_str()), 485 entry("ADDRESS=%s", channelConf->ipaddr.c_str()), 486 entry("GATEWAY=%s", channelConf->gateway.c_str()), 487 entry("VLAN=%d", channelConf->vlanID)); 488 489 log<level::INFO>("Use Set Channel Access command to apply"); 490 } 491 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress 492 { 493 channelConf->lan_set_in_progress = SET_IN_PROGRESS; 494 } 495 } 496 break; 497 498 default: 499 { 500 rc = IPMI_CC_PARM_NOT_SUPPORTED; 501 } 502 } 503 504 return rc; 505 } 506 507 struct get_lan_t 508 { 509 uint8_t rev_channel; 510 uint8_t parameter; 511 uint8_t parameter_set; 512 uint8_t parameter_block; 513 } __attribute__((packed)); 514 515 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, 516 ipmi_cmd_t cmd, 517 ipmi_request_t request, 518 ipmi_response_t response, 519 ipmi_data_len_t data_len, 520 ipmi_context_t context) 521 { 522 ipmi_ret_t rc = IPMI_CC_OK; 523 *data_len = 0; 524 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 525 526 get_lan_t *reqptr = (get_lan_t*) request; 527 // channel number is the lower nibble 528 int channel = reqptr->rev_channel & CHANNEL_MASK; 529 530 if (reqptr->rev_channel & 0x80) // Revision is bit 7 531 { 532 // Only current revision was requested 533 *data_len = sizeof(current_revision); 534 memcpy(response, ¤t_revision, *data_len); 535 return IPMI_CC_OK; 536 } 537 538 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 539 if (ethdevice.empty()) 540 { 541 return IPMI_CC_INVALID_FIELD_REQUEST; 542 } 543 auto channelConf = getChannelConfig(channel); 544 545 if (reqptr->parameter == LAN_PARM_INPROGRESS) 546 { 547 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress}; 548 *data_len = sizeof(buf); 549 memcpy(response, &buf, *data_len); 550 } 551 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT) 552 { 553 uint8_t buf[] = {current_revision,0x04}; 554 *data_len = sizeof(buf); 555 memcpy(response, &buf, *data_len); 556 } 557 else if (reqptr->parameter == LAN_PARM_AUTHENABLES) 558 { 559 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04}; 560 *data_len = sizeof(buf); 561 memcpy(response, &buf, *data_len); 562 } 563 else if ((reqptr->parameter == LAN_PARM_IP) || 564 (reqptr->parameter == LAN_PARM_SUBNET) || 565 (reqptr->parameter == LAN_PARM_GATEWAY) || 566 (reqptr->parameter == LAN_PARM_MAC)) 567 { 568 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {}; 569 570 *data_len = sizeof(current_revision); 571 memcpy(buf, ¤t_revision, *data_len); 572 573 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 574 { 575 if (reqptr->parameter == LAN_PARM_MAC) 576 { 577 *data_len = sizeof(buf); 578 } 579 else 580 { 581 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1; 582 } 583 memcpy(response, &buf, *data_len); 584 } 585 else 586 { 587 rc = IPMI_CC_UNSPECIFIED_ERROR; 588 } 589 } 590 else if (reqptr->parameter == LAN_PARM_VLAN) 591 { 592 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {}; 593 594 *data_len = sizeof(current_revision); 595 memcpy(buf, ¤t_revision, *data_len); 596 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 597 { 598 *data_len = sizeof(buf); 599 memcpy(response, &buf, *data_len); 600 } 601 } 602 else if (reqptr->parameter == LAN_PARM_IPSRC) 603 { 604 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {}; 605 *data_len = sizeof(current_revision); 606 memcpy(buff, ¤t_revision, *data_len); 607 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK) 608 { 609 *data_len = sizeof(buff); 610 memcpy(response, &buff, *data_len); 611 } 612 } 613 else 614 { 615 log<level::ERR>("Unsupported parameter", 616 entry("PARAMETER=0x%x", reqptr->parameter)); 617 rc = IPMI_CC_PARM_NOT_SUPPORTED; 618 } 619 620 return rc; 621 } 622 623 void register_netfn_transport_functions() 624 { 625 // <Wildcard Command> 626 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD); 627 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard, 628 PRIVILEGE_USER); 629 630 // <Set LAN Configuration Parameters> 631 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN); 632 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan, 633 PRIVILEGE_ADMIN); 634 635 // <Get LAN Configuration Parameters> 636 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN); 637 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan, 638 PRIVILEGE_OPERATOR); 639 640 return; 641 } 642