1 #include <chrono> 2 #include <fstream> 3 #include <stdio.h> 4 #include <string.h> 5 #include <stdint.h> 6 #include <arpa/inet.h> 7 #include <string> 8 #include <experimental/filesystem> 9 10 #include "app/channel.hpp" 11 #include "host-ipmid/ipmid-api.h" 12 #include "ipmid.hpp" 13 #include "timer.hpp" 14 #include "transporthandler.hpp" 15 #include "utils.hpp" 16 #include "net.hpp" 17 18 #include <phosphor-logging/log.hpp> 19 #include <phosphor-logging/elog-errors.hpp> 20 #include "xyz/openbmc_project/Common/error.hpp" 21 22 #define SYSTEMD_NETWORKD_DBUS 1 23 24 #ifdef SYSTEMD_NETWORKD_DBUS 25 #include <systemd/sd-bus.h> 26 #include <mapper.h> 27 #endif 28 29 extern std::unique_ptr<phosphor::ipmi::Timer> networkTimer; 30 31 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx 32 constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 33 34 std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; 35 36 using namespace phosphor::logging; 37 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 38 39 namespace fs = std::experimental::filesystem; 40 41 void register_netfn_transport_functions() __attribute__((constructor)); 42 43 struct ChannelConfig_t* getChannelConfig(int channel) 44 { 45 auto item = channelConfig.find(channel); 46 if (item == channelConfig.end()) 47 { 48 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>(); 49 } 50 51 return channelConfig[channel].get(); 52 } 53 54 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or 55 // Cache based on Set-In-Progress State 56 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel) 57 { 58 ipmi_ret_t rc = IPMI_CC_OK; 59 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 60 61 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 62 // if ethdevice is an empty string they weren't expecting this channel. 63 if (ethdevice.empty()) 64 { 65 // TODO: return error from getNetworkData() 66 return IPMI_CC_INVALID_FIELD_REQUEST; 67 } 68 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE; 69 auto channelConf = getChannelConfig(channel); 70 71 try 72 { 73 switch (lan_param) 74 { 75 case LAN_PARM_IP: 76 { 77 std::string ipaddress; 78 if (channelConf->lan_set_in_progress == SET_COMPLETE) 79 { 80 try 81 { 82 auto ipObjectInfo = ipmi::getIPObject( 83 bus, 84 ipmi::network::IP_INTERFACE, 85 ipmi::network::ROOT, 86 ethIP); 87 88 auto properties = ipmi::getAllDbusProperties( 89 bus, 90 ipObjectInfo.second, 91 ipObjectInfo.first, 92 ipmi::network::IP_INTERFACE); 93 94 ipaddress = properties["Address"].get<std::string>(); 95 } 96 // ignore the exception, as it is a valid condition that 97 // the system is not configured with any IP. 98 catch (InternalFailure& e) 99 { 100 // nothing to do. 101 } 102 } 103 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 104 { 105 ipaddress = channelConf->ipaddr; 106 } 107 108 inet_pton(AF_INET, ipaddress.c_str(), 109 reinterpret_cast<void*>(data)); 110 } 111 break; 112 113 case LAN_PARM_IPSRC: 114 { 115 std::string networkInterfacePath; 116 117 if (channelConf->lan_set_in_progress == SET_COMPLETE) 118 { 119 try 120 { 121 ipmi::ObjectTree ancestorMap; 122 // if the system is having ip object,then 123 // get the IP object. 124 auto ipObject = ipmi::getDbusObject( 125 bus, 126 ipmi::network::IP_INTERFACE, 127 ipmi::network::ROOT, 128 ethIP); 129 130 // Get the parent interface of the IP object. 131 try 132 { 133 ipmi::InterfaceList interfaces; 134 interfaces.emplace_back( 135 ipmi::network::ETHERNET_INTERFACE); 136 137 ancestorMap = ipmi::getAllAncestors( 138 bus, 139 ipObject.first, 140 std::move(interfaces)); 141 } 142 catch (InternalFailure& e) 143 { 144 // if unable to get the parent interface 145 // then commit the error and return. 146 log<level::ERR>("Unable to get the parent interface", 147 entry("PATH=%s", ipObject.first.c_str()), 148 entry("INTERFACE=%s", 149 ipmi::network::ETHERNET_INTERFACE)); 150 break; 151 152 } 153 // for an ip object there would be single parent 154 // interface. 155 networkInterfacePath = ancestorMap.begin()->first; 156 } 157 catch (InternalFailure& e) 158 { 159 // if there is no ip configured on the system,then 160 // get the network interface object. 161 auto networkInterfaceObject = ipmi::getDbusObject( 162 bus, 163 ipmi::network::ETHERNET_INTERFACE, 164 ipmi::network::ROOT, 165 ethdevice); 166 167 networkInterfacePath = networkInterfaceObject.first; 168 } 169 170 auto variant = ipmi::getDbusProperty( 171 bus, 172 ipmi::network::SERVICE, 173 networkInterfacePath, 174 ipmi::network::ETHERNET_INTERFACE, 175 "DHCPEnabled"); 176 177 auto dhcpEnabled = variant.get<bool>(); 178 // As per IPMI spec 2=>DHCP, 1=STATIC 179 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP : 180 ipmi::network::IPOrigin::STATIC; 181 182 memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE); 183 } 184 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 185 { 186 memcpy(data, &(channelConf->ipsrc), 187 ipmi::network::IPSRC_SIZE_BYTE); 188 } 189 } 190 break; 191 192 case LAN_PARM_SUBNET: 193 { 194 unsigned long mask {}; 195 if (channelConf->lan_set_in_progress == SET_COMPLETE) 196 { 197 try 198 { 199 auto ipObjectInfo = ipmi::getIPObject( 200 bus, 201 ipmi::network::IP_INTERFACE, 202 ipmi::network::ROOT, 203 ipmi::network::IP_TYPE); 204 205 auto properties = ipmi::getAllDbusProperties( 206 bus, 207 ipObjectInfo.second, 208 ipObjectInfo.first, 209 ipmi::network::IP_INTERFACE); 210 211 auto prefix = properties["PrefixLength"].get<uint8_t>(); 212 mask = ipmi::network::MASK_32_BIT; 213 mask = htonl(mask << (ipmi::network::BITS_32 - prefix)); 214 } 215 // ignore the exception, as it is a valid condition that 216 // the system is not configured with any IP. 217 catch (InternalFailure& e) 218 { 219 // nothing to do 220 } 221 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE); 222 } 223 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 224 { 225 inet_pton(AF_INET, channelConf->netmask.c_str(), 226 reinterpret_cast<void*>(data)); 227 } 228 229 } 230 break; 231 232 case LAN_PARM_GATEWAY: 233 { 234 std::string gateway; 235 236 if (channelConf->lan_set_in_progress == SET_COMPLETE) 237 { 238 try 239 { 240 auto systemObject = ipmi::getDbusObject( 241 bus, 242 ipmi::network::SYSTEMCONFIG_INTERFACE, 243 ipmi::network::ROOT); 244 245 auto systemProperties = ipmi::getAllDbusProperties( 246 bus, 247 systemObject.second, 248 systemObject.first, 249 ipmi::network::SYSTEMCONFIG_INTERFACE); 250 251 gateway = systemProperties["DefaultGateway"].get< 252 std::string>(); 253 } 254 // ignore the exception, as it is a valid condition that 255 // the system is not configured with any IP. 256 catch (InternalFailure& e) 257 { 258 // nothing to do 259 } 260 261 } 262 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 263 { 264 gateway = channelConf->gateway; 265 } 266 267 inet_pton(AF_INET, gateway.c_str(), 268 reinterpret_cast<void*>(data)); 269 } 270 break; 271 272 case LAN_PARM_MAC: 273 { 274 std::string macAddress; 275 if (channelConf->lan_set_in_progress == SET_COMPLETE) 276 { 277 auto macObjectInfo = ipmi::getDbusObject( 278 bus, 279 ipmi::network::MAC_INTERFACE, 280 ipmi::network::ROOT, 281 ethdevice); 282 283 auto variant = ipmi::getDbusProperty( 284 bus, 285 macObjectInfo.second, 286 macObjectInfo.first, 287 ipmi::network::MAC_INTERFACE, 288 "MACAddress"); 289 290 macAddress = variant.get<std::string>(); 291 292 } 293 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 294 { 295 macAddress = channelConf->macAddress; 296 } 297 298 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 299 (data), 300 (data + 1), 301 (data + 2), 302 (data + 3), 303 (data + 4), 304 (data + 5)); 305 } 306 break; 307 308 case LAN_PARM_VLAN: 309 { 310 uint16_t vlanID {}; 311 if (channelConf->lan_set_in_progress == SET_COMPLETE) 312 { 313 try 314 { 315 auto ipObjectInfo = ipmi::getIPObject( 316 bus, 317 ipmi::network::IP_INTERFACE, 318 ipmi::network::ROOT, 319 ipmi::network::IP_TYPE); 320 321 vlanID = static_cast<uint16_t>( 322 ipmi::network::getVLAN(ipObjectInfo.first)); 323 324 vlanID = htole16(vlanID); 325 326 if (vlanID) 327 { 328 //Enable the 16th bit 329 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK); 330 } 331 } 332 // ignore the exception, as it is a valid condition that 333 // the system is not configured with any IP. 334 catch (InternalFailure& e) 335 { 336 // nothing to do 337 } 338 339 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE); 340 } 341 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 342 { 343 memcpy(data, &(channelConf->vlanID), 344 ipmi::network::VLAN_SIZE_BYTE); 345 } 346 } 347 break; 348 349 default: 350 rc = IPMI_CC_PARM_OUT_OF_RANGE; 351 } 352 } 353 catch (InternalFailure& e) 354 { 355 commit<InternalFailure>(); 356 rc = IPMI_CC_UNSPECIFIED_ERROR; 357 return rc; 358 } 359 return rc; 360 } 361 362 namespace cipher 363 { 364 365 std::vector<uint8_t> getCipherList() 366 { 367 std::vector<uint8_t> cipherList; 368 369 std::ifstream jsonFile(configFile); 370 if (!jsonFile.is_open()) 371 { 372 log<level::ERR>("Channel Cipher suites file not found"); 373 elog<InternalFailure>(); 374 } 375 376 auto data = Json::parse(jsonFile, nullptr, false); 377 if (data.is_discarded()) 378 { 379 log<level::ERR>("Parsing channel cipher suites JSON failed"); 380 elog<InternalFailure>(); 381 } 382 383 // Byte 1 is reserved 384 cipherList.push_back(0x00); 385 386 for (const auto& record : data) 387 { 388 cipherList.push_back(record.value(cipher, 0)); 389 } 390 391 return cipherList; 392 } 393 394 } //namespace cipher 395 396 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 397 ipmi_request_t request, ipmi_response_t response, 398 ipmi_data_len_t data_len, ipmi_context_t context) 399 { 400 // Status code. 401 ipmi_ret_t rc = IPMI_CC_INVALID; 402 *data_len = 0; 403 return rc; 404 } 405 406 struct set_lan_t 407 { 408 uint8_t channel; 409 uint8_t parameter; 410 uint8_t data[8]; // Per IPMI spec, not expecting more than this size 411 } __attribute__((packed)); 412 413 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, 414 ipmi_cmd_t cmd, 415 ipmi_request_t request, 416 ipmi_response_t response, 417 ipmi_data_len_t data_len, 418 ipmi_context_t context) 419 { 420 ipmi_ret_t rc = IPMI_CC_OK; 421 *data_len = 0; 422 423 using namespace std::chrono_literals; 424 425 // time to wait before applying the network changes. 426 constexpr auto networkTimeout = 10000000us; // 10 sec 427 428 char ipaddr[INET_ADDRSTRLEN]; 429 char netmask[INET_ADDRSTRLEN]; 430 char gateway[INET_ADDRSTRLEN]; 431 432 auto reqptr = reinterpret_cast<const set_lan_t*>(request); 433 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 434 435 // channel number is the lower nibble 436 int channel = reqptr->channel & CHANNEL_MASK; 437 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 438 if (ethdevice.empty()) 439 { 440 return IPMI_CC_INVALID_FIELD_REQUEST; 441 } 442 auto channelConf = getChannelConfig(channel); 443 444 switch (reqptr->parameter) 445 { 446 case LAN_PARM_IP: 447 { 448 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 449 reqptr->data[0], reqptr->data[1], 450 reqptr->data[2], reqptr->data[3]); 451 452 channelConf->ipaddr.assign(ipaddr); 453 } 454 break; 455 456 case LAN_PARM_IPSRC: 457 { 458 uint8_t ipsrc{}; 459 memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); 460 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); 461 } 462 break; 463 464 case LAN_PARM_MAC: 465 { 466 char mac[SIZE_MAC]; 467 468 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 469 reqptr->data[0], 470 reqptr->data[1], 471 reqptr->data[2], 472 reqptr->data[3], 473 reqptr->data[4], 474 reqptr->data[5]); 475 476 auto macObjectInfo = ipmi::getDbusObject( 477 bus, 478 ipmi::network::MAC_INTERFACE, 479 ipmi::network::ROOT, 480 ethdevice); 481 482 ipmi::setDbusProperty(bus, 483 macObjectInfo.second, 484 macObjectInfo.first, 485 ipmi::network::MAC_INTERFACE, 486 "MACAddress", 487 std::string(mac)); 488 489 channelConf->macAddress = mac; 490 } 491 break; 492 493 case LAN_PARM_SUBNET: 494 { 495 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 496 reqptr->data[0], reqptr->data[1], 497 reqptr->data[2], reqptr->data[3]); 498 channelConf->netmask.assign(netmask); 499 } 500 break; 501 502 case LAN_PARM_GATEWAY: 503 { 504 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT, 505 reqptr->data[0], reqptr->data[1], 506 reqptr->data[2], reqptr->data[3]); 507 channelConf->gateway.assign(gateway); 508 } 509 break; 510 511 case LAN_PARM_VLAN: 512 { 513 uint16_t vlan {}; 514 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); 515 // We are not storing the enable bit 516 // We assume that ipmitool always send enable 517 // bit as 1. 518 vlan = le16toh(vlan); 519 channelConf->vlanID = vlan; 520 } 521 break; 522 523 case LAN_PARM_INPROGRESS: 524 { 525 if (reqptr->data[0] == SET_COMPLETE) 526 { 527 channelConf->lan_set_in_progress = SET_COMPLETE; 528 529 log<level::INFO>("Network data from Cache", 530 entry("PREFIX=%s", channelConf->netmask.c_str()), 531 entry("ADDRESS=%s", channelConf->ipaddr.c_str()), 532 entry("GATEWAY=%s", channelConf->gateway.c_str()), 533 entry("VLAN=%d", channelConf->vlanID)); 534 535 if (!networkTimer) 536 { 537 log<level::ERR>("Network timer is not instantiated"); 538 return IPMI_CC_UNSPECIFIED_ERROR; 539 } 540 541 // start/restart the timer 542 networkTimer->startTimer(networkTimeout); 543 } 544 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress 545 { 546 channelConf->lan_set_in_progress = SET_IN_PROGRESS; 547 channelConf->flush = true; 548 } 549 } 550 break; 551 552 default: 553 { 554 rc = IPMI_CC_PARM_NOT_SUPPORTED; 555 } 556 } 557 558 return rc; 559 } 560 561 struct get_lan_t 562 { 563 uint8_t rev_channel; 564 uint8_t parameter; 565 uint8_t parameter_set; 566 uint8_t parameter_block; 567 } __attribute__((packed)); 568 569 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, 570 ipmi_cmd_t cmd, 571 ipmi_request_t request, 572 ipmi_response_t response, 573 ipmi_data_len_t data_len, 574 ipmi_context_t context) 575 { 576 ipmi_ret_t rc = IPMI_CC_OK; 577 *data_len = 0; 578 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 579 580 get_lan_t *reqptr = (get_lan_t*) request; 581 // channel number is the lower nibble 582 int channel = reqptr->rev_channel & CHANNEL_MASK; 583 584 if (reqptr->rev_channel & 0x80) // Revision is bit 7 585 { 586 // Only current revision was requested 587 *data_len = sizeof(current_revision); 588 memcpy(response, ¤t_revision, *data_len); 589 return IPMI_CC_OK; 590 } 591 592 static std::vector<uint8_t> cipherList; 593 static auto listInit = false; 594 595 if (!listInit) 596 { 597 try 598 { 599 cipherList = cipher::getCipherList(); 600 listInit = true; 601 } 602 catch (const std::exception &e) 603 { 604 return IPMI_CC_UNSPECIFIED_ERROR; 605 } 606 } 607 608 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 609 if (ethdevice.empty()) 610 { 611 return IPMI_CC_INVALID_FIELD_REQUEST; 612 } 613 auto channelConf = getChannelConfig(channel); 614 615 if (reqptr->parameter == LAN_PARM_INPROGRESS) 616 { 617 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress}; 618 *data_len = sizeof(buf); 619 memcpy(response, &buf, *data_len); 620 } 621 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT) 622 { 623 uint8_t buf[] = {current_revision,0x04}; 624 *data_len = sizeof(buf); 625 memcpy(response, &buf, *data_len); 626 } 627 else if (reqptr->parameter == LAN_PARM_AUTHENABLES) 628 { 629 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04}; 630 *data_len = sizeof(buf); 631 memcpy(response, &buf, *data_len); 632 } 633 else if ((reqptr->parameter == LAN_PARM_IP) || 634 (reqptr->parameter == LAN_PARM_SUBNET) || 635 (reqptr->parameter == LAN_PARM_GATEWAY) || 636 (reqptr->parameter == LAN_PARM_MAC)) 637 { 638 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {}; 639 640 *data_len = sizeof(current_revision); 641 memcpy(buf, ¤t_revision, *data_len); 642 643 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 644 { 645 if (reqptr->parameter == LAN_PARM_MAC) 646 { 647 *data_len = sizeof(buf); 648 } 649 else 650 { 651 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1; 652 } 653 memcpy(response, &buf, *data_len); 654 } 655 else 656 { 657 rc = IPMI_CC_UNSPECIFIED_ERROR; 658 } 659 } 660 else if (reqptr->parameter == LAN_PARM_VLAN) 661 { 662 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {}; 663 664 *data_len = sizeof(current_revision); 665 memcpy(buf, ¤t_revision, *data_len); 666 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 667 { 668 *data_len = sizeof(buf); 669 memcpy(response, &buf, *data_len); 670 } 671 } 672 else if (reqptr->parameter == LAN_PARM_IPSRC) 673 { 674 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {}; 675 *data_len = sizeof(current_revision); 676 memcpy(buff, ¤t_revision, *data_len); 677 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK) 678 { 679 *data_len = sizeof(buff); 680 memcpy(response, &buff, *data_len); 681 } 682 } 683 else if (reqptr->parameter == CIPHER_SUITE_COUNT) 684 { 685 *(static_cast<uint8_t*>(response)) = current_revision; 686 // Byte 1 is reserved byte and does not indicate a cipher suite ID, so 687 // no of cipher suite entry count is one less than the size of the 688 // vector 689 auto count = static_cast<uint8_t>(cipherList.size() - 1); 690 *(static_cast<uint8_t*>(response) + 1) = count; 691 *data_len = sizeof(current_revision) + sizeof(count); 692 } 693 else if (reqptr->parameter == CIPHER_SUITE_ENTRIES) 694 { 695 *(static_cast<uint8_t*>(response)) = current_revision; 696 // Byte 1 is reserved 697 std::copy_n(cipherList.data(), 698 cipherList.size(), 699 static_cast<uint8_t*>(response) + 1); 700 *data_len = sizeof(current_revision) + 701 static_cast<uint8_t>(cipherList.size()); 702 } 703 else 704 { 705 log<level::ERR>("Unsupported parameter", 706 entry("PARAMETER=0x%x", reqptr->parameter)); 707 rc = IPMI_CC_PARM_NOT_SUPPORTED; 708 } 709 710 return rc; 711 } 712 713 void applyChanges(int channel) 714 { 715 std::string ipaddress; 716 std::string gateway; 717 uint8_t prefix {}; 718 uint32_t vlanID {}; 719 std::string networkInterfacePath; 720 ipmi::DbusObjectInfo ipObject; 721 ipmi::DbusObjectInfo systemObject; 722 723 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 724 if (ethdevice.empty()) 725 { 726 log<level::ERR>("Unable to get the interface name", 727 entry("CHANNEL=%d", channel)); 728 return; 729 } 730 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE; 731 auto channelConf = getChannelConfig(channel); 732 733 try 734 { 735 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 736 737 log<level::INFO>("Network data from Cache", 738 entry("PREFIX=%s", channelConf->netmask.c_str()), 739 entry("ADDRESS=%s", channelConf->ipaddr.c_str()), 740 entry("GATEWAY=%s", channelConf->gateway.c_str()), 741 entry("VLAN=%d", channelConf->vlanID), 742 entry("IPSRC=%d", channelConf->ipsrc)); 743 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK) 744 { 745 //get the first twelve bits which is vlan id 746 //not interested in rest of the bits. 747 channelConf->vlanID = le32toh(channelConf->vlanID); 748 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK; 749 } 750 751 // if the asked ip src is DHCP then not interested in 752 // any given data except vlan. 753 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP) 754 { 755 // always get the system object 756 systemObject = ipmi::getDbusObject( 757 bus, 758 ipmi::network::SYSTEMCONFIG_INTERFACE, 759 ipmi::network::ROOT); 760 761 // the below code is to determine the mode of the interface 762 // as the handling is same, if the system is configured with 763 // DHCP or user has given all the data. 764 try 765 { 766 ipmi::ObjectTree ancestorMap; 767 768 ipmi::InterfaceList interfaces { 769 ipmi::network::ETHERNET_INTERFACE }; 770 771 // if the system is having ip object,then 772 // get the IP object. 773 ipObject = ipmi::getIPObject(bus, 774 ipmi::network::IP_INTERFACE, 775 ipmi::network::ROOT, 776 ethIp); 777 778 // Get the parent interface of the IP object. 779 try 780 { 781 ancestorMap = ipmi::getAllAncestors(bus, 782 ipObject.first, 783 std::move(interfaces)); 784 } 785 catch (InternalFailure& e) 786 { 787 // if unable to get the parent interface 788 // then commit the error and return. 789 log<level::ERR>("Unable to get the parent interface", 790 entry("PATH=%s", ipObject.first.c_str()), 791 entry("INTERFACE=%s", 792 ipmi::network::ETHERNET_INTERFACE)); 793 commit<InternalFailure>(); 794 channelConf->clear(); 795 return; 796 } 797 798 networkInterfacePath = ancestorMap.begin()->first; 799 } 800 catch (InternalFailure& e) 801 { 802 // TODO Currently IPMI supports single interface,need to handle 803 // Multiple interface through 804 // https://github.com/openbmc/openbmc/issues/2138 805 806 // if there is no ip configured on the system,then 807 // get the network interface object. 808 auto networkInterfaceObject = ipmi::getDbusObject( 809 bus, 810 ipmi::network::ETHERNET_INTERFACE, 811 ipmi::network::ROOT, 812 ethdevice); 813 814 networkInterfacePath = std::move(networkInterfaceObject.first); 815 } 816 817 // get the configured mode on the system. 818 auto enableDHCP = ipmi::getDbusProperty( 819 bus, 820 ipmi::network::SERVICE, 821 networkInterfacePath, 822 ipmi::network::ETHERNET_INTERFACE, 823 "DHCPEnabled").get<bool>(); 824 825 // if ip address source is not given then get the ip source mode 826 // from the system so that it can be applied later. 827 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED) 828 { 829 channelConf->ipsrc = (enableDHCP) ? 830 ipmi::network::IPOrigin::DHCP : 831 ipmi::network::IPOrigin::STATIC; 832 } 833 834 // check whether user has given all the data 835 // or the configured system interface is dhcp enabled, 836 // in both of the cases get the values from the cache. 837 if ((!channelConf->ipaddr.empty() && 838 !channelConf->netmask.empty() && 839 !channelConf->gateway.empty()) || 840 (enableDHCP)) // configured system interface mode = DHCP 841 { 842 //convert mask into prefix 843 ipaddress = channelConf->ipaddr; 844 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask); 845 gateway = channelConf->gateway; 846 } 847 else // asked ip src = static and configured system src = static 848 // or partially given data. 849 { 850 // We have partial filled cache so get the remaining 851 // info from the system. 852 853 // Get the network data from the system as user has 854 // not given all the data then use the data fetched from the 855 // system but it is implementation dependent,IPMI spec doesn't 856 // force it. 857 858 // if system is not having any ip object don't throw error, 859 try 860 { 861 auto properties = ipmi::getAllDbusProperties( 862 bus, 863 ipObject.second, 864 ipObject.first, 865 ipmi::network::IP_INTERFACE); 866 867 ipaddress = channelConf->ipaddr.empty() ? 868 properties["Address"].get<std::string>() : 869 channelConf->ipaddr; 870 871 prefix = channelConf->netmask.empty() ? 872 properties["PrefixLength"].get<uint8_t>() : 873 ipmi::network::toPrefix(AF_INET, 874 channelConf->netmask); 875 } 876 catch (InternalFailure& e) 877 { 878 log<level::INFO>("Failed to get IP object which matches", 879 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE), 880 entry("MATCH=%s", ethIp)); 881 } 882 883 auto systemProperties = ipmi::getAllDbusProperties( 884 bus, 885 systemObject.second, 886 systemObject.first, 887 ipmi::network::SYSTEMCONFIG_INTERFACE); 888 889 gateway = channelConf->gateway.empty() ? 890 systemProperties["DefaultGateway"].get<std::string>() : 891 channelConf->gateway; 892 } 893 } 894 895 // Currently network manager doesn't support purging of all the 896 // ip addresses and the vlan interfaces from the parent interface, 897 // TODO once the support is there, will make the change here. 898 // https://github.com/openbmc/openbmc/issues/2141. 899 900 // TODO Currently IPMI supports single interface,need to handle 901 // Multiple interface through 902 // https://github.com/openbmc/openbmc/issues/2138 903 904 // instead of deleting all the vlan interfaces and 905 // all the ipv4 address,we will call reset method. 906 //delete all the vlan interfaces 907 908 ipmi::deleteAllDbusObjects(bus, 909 ipmi::network::ROOT, 910 ipmi::network::VLAN_INTERFACE); 911 912 // set the interface mode to static 913 auto networkInterfaceObject = ipmi::getDbusObject( 914 bus, 915 ipmi::network::ETHERNET_INTERFACE, 916 ipmi::network::ROOT, 917 ethdevice); 918 919 // setting the physical interface mode to static. 920 ipmi::setDbusProperty(bus, 921 ipmi::network::SERVICE, 922 networkInterfaceObject.first, 923 ipmi::network::ETHERNET_INTERFACE, 924 "DHCPEnabled", 925 false); 926 927 networkInterfacePath = networkInterfaceObject.first; 928 929 //delete all the ipv4 addresses 930 ipmi::deleteAllDbusObjects(bus, 931 ipmi::network::ROOT, 932 ipmi::network::IP_INTERFACE, 933 ethIp); 934 935 if (vlanID) 936 { 937 ipmi::network::createVLAN(bus, 938 ipmi::network::SERVICE, 939 ipmi::network::ROOT, 940 ethdevice, 941 vlanID); 942 943 auto networkInterfaceObject = ipmi::getDbusObject( 944 bus, 945 ipmi::network::VLAN_INTERFACE, 946 ipmi::network::ROOT); 947 948 networkInterfacePath = networkInterfaceObject.first; 949 } 950 951 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP) 952 { 953 ipmi::setDbusProperty(bus, 954 ipmi::network::SERVICE, 955 networkInterfacePath, 956 ipmi::network::ETHERNET_INTERFACE, 957 "DHCPEnabled", 958 true); 959 } 960 else 961 { 962 //change the mode to static 963 ipmi::setDbusProperty(bus, 964 ipmi::network::SERVICE, 965 networkInterfacePath, 966 ipmi::network::ETHERNET_INTERFACE, 967 "DHCPEnabled", 968 false); 969 970 if (!ipaddress.empty()) 971 { 972 ipmi::network::createIP(bus, 973 ipmi::network::SERVICE, 974 networkInterfacePath, 975 ipv4Protocol, 976 ipaddress, 977 prefix); 978 } 979 980 if (!gateway.empty()) 981 { 982 ipmi::setDbusProperty(bus, 983 systemObject.second, 984 systemObject.first, 985 ipmi::network::SYSTEMCONFIG_INTERFACE, 986 "DefaultGateway", 987 std::string(gateway)); 988 } 989 } 990 991 } 992 catch (InternalFailure& e) 993 { 994 log<level::ERR>("Failed to set network data", 995 entry("PREFIX=%d", prefix), 996 entry("ADDRESS=%s", ipaddress.c_str()), 997 entry("GATEWAY=%s", gateway.c_str()), 998 entry("VLANID=%d", vlanID), 999 entry("IPSRC=%d", channelConf->ipsrc)); 1000 1001 commit<InternalFailure>(); 1002 } 1003 1004 channelConf->clear(); 1005 } 1006 1007 void commitNetworkChanges() 1008 { 1009 for (const auto &channel : channelConfig) 1010 { 1011 if (channel.second->flush) 1012 { 1013 applyChanges(channel.first); 1014 } 1015 } 1016 } 1017 1018 void createNetworkTimer() 1019 { 1020 if (!networkTimer) 1021 { 1022 std::function<void()> networkTimerCallback( 1023 std::bind(&commitNetworkChanges)); 1024 1025 networkTimer = 1026 std::make_unique<phosphor::ipmi::Timer>( 1027 ipmid_get_sd_event_connection(), 1028 networkTimerCallback); 1029 } 1030 1031 } 1032 1033 void register_netfn_transport_functions() 1034 { 1035 // As this timer is only for transport handler 1036 // so creating it here. 1037 createNetworkTimer(); 1038 // <Wildcard Command> 1039 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard, 1040 PRIVILEGE_USER); 1041 1042 // <Set LAN Configuration Parameters> 1043 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan, 1044 PRIVILEGE_ADMIN); 1045 1046 // <Get LAN Configuration Parameters> 1047 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan, 1048 PRIVILEGE_OPERATOR); 1049 1050 return; 1051 } 1052