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