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