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