1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include "channel_mgmt.hpp" 18 19 #include "apphandler.hpp" 20 #include "user_layer.hpp" 21 22 #include <ifaddrs.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include <boost/interprocess/sync/scoped_lock.hpp> 28 #include <phosphor-logging/log.hpp> 29 #include <sdbusplus/bus/match.hpp> 30 #include <sdbusplus/server/object.hpp> 31 32 #include <cerrno> 33 #include <exception> 34 #include <filesystem> 35 #include <fstream> 36 #include <unordered_map> 37 38 namespace ipmi 39 { 40 41 using namespace phosphor::logging; 42 43 static constexpr const char* channelAccessDefaultFilename = 44 "/usr/share/ipmi-providers/channel_access.json"; 45 static constexpr const char* channelConfigDefaultFilename = 46 "/usr/share/ipmi-providers/channel_config.json"; 47 static constexpr const char* channelNvDataFilename = 48 "/var/lib/ipmi/channel_access_nv.json"; 49 static constexpr const char* channelVolatileDataFilename = 50 "/run/ipmi/channel_access_volatile.json"; 51 52 // TODO: Get the service name dynamically.. 53 static constexpr const char* networkIntfServiceName = 54 "xyz.openbmc_project.Network"; 55 static constexpr const char* networkIntfObjectBasePath = 56 "/xyz/openbmc_project/network"; 57 static constexpr const char* networkChConfigIntfName = 58 "xyz.openbmc_project.Channel.ChannelAccess"; 59 static constexpr const char* privilegePropertyString = "MaxPrivilege"; 60 static constexpr const char* dBusPropertiesInterface = 61 "org.freedesktop.DBus.Properties"; 62 static constexpr const char* propertiesChangedSignal = "PropertiesChanged"; 63 static constexpr const char* interfaceAddedSignal = "InterfacesAdded"; 64 static constexpr const char* interfaceRemovedSignal = "InterfacesRemoved"; 65 66 // STRING DEFINES: Should sync with key's in JSON 67 static constexpr const char* nameString = "name"; 68 static constexpr const char* isValidString = "is_valid"; 69 static constexpr const char* activeSessionsString = "active_sessions"; 70 static constexpr const char* maxTransferSizeString = "max_transfer_size"; 71 static constexpr const char* channelInfoString = "channel_info"; 72 static constexpr const char* mediumTypeString = "medium_type"; 73 static constexpr const char* protocolTypeString = "protocol_type"; 74 static constexpr const char* sessionSupportedString = "session_supported"; 75 static constexpr const char* isIpmiString = "is_ipmi"; 76 static constexpr const char* isManagementNIC = "is_management_nic"; 77 static constexpr const char* authTypeSupportedString = "auth_type_supported"; 78 static constexpr const char* accessModeString = "access_mode"; 79 static constexpr const char* userAuthDisabledString = "user_auth_disabled"; 80 static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled"; 81 static constexpr const char* alertingDisabledString = "alerting_disabled"; 82 static constexpr const char* privLimitString = "priv_limit"; 83 static constexpr const char* authTypeEnabledString = "auth_type_enabled"; 84 85 // Default values 86 static constexpr const char* defaultChannelName = "RESERVED"; 87 static constexpr const uint8_t defaultMediumType = 88 static_cast<uint8_t>(EChannelMediumType::reserved); 89 static constexpr const uint8_t defaultProtocolType = 90 static_cast<uint8_t>(EChannelProtocolType::reserved); 91 static constexpr const uint8_t defaultSessionSupported = 92 static_cast<uint8_t>(EChannelSessSupported::none); 93 static constexpr const uint8_t defaultAuthType = 94 static_cast<uint8_t>(EAuthType::none); 95 static constexpr const bool defaultIsIpmiState = false; 96 static constexpr size_t smallChannelSize = 64; 97 98 std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal 99 __attribute__((init_priority(101))); 100 101 std::unique_ptr<sdbusplus::bus::match_t> chInterfaceAddedSignal 102 __attribute__((init_priority(101))); 103 104 std::unique_ptr<sdbusplus::bus::match_t> chInterfaceRemovedSignal 105 __attribute__((init_priority(101))); 106 107 // String mappings use in JSON config file 108 static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = { 109 {"reserved", EChannelMediumType::reserved}, 110 {"ipmb", EChannelMediumType::ipmb}, 111 {"icmb-v1.0", EChannelMediumType::icmbV10}, 112 {"icmb-v0.9", EChannelMediumType::icmbV09}, 113 {"lan-802.3", EChannelMediumType::lan8032}, 114 {"serial", EChannelMediumType::serial}, 115 {"other-lan", EChannelMediumType::otherLan}, 116 {"pci-smbus", EChannelMediumType::pciSmbus}, 117 {"smbus-v1.0", EChannelMediumType::smbusV11}, 118 {"smbus-v2.0", EChannelMediumType::smbusV20}, 119 {"usb-1x", EChannelMediumType::usbV1x}, 120 {"usb-2x", EChannelMediumType::usbV2x}, 121 {"system-interface", EChannelMediumType::systemInterface}, 122 {"oem", EChannelMediumType::oem}, 123 {"unknown", EChannelMediumType::unknown}}; 124 125 static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = { 126 {interfaceKCS, "SMS"}, 127 {interfaceLAN1, "eth0"}, 128 {interfaceUnknown, "unknown"}}; 129 130 static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = { 131 {"na", EChannelProtocolType::na}, 132 {"ipmb-1.0", EChannelProtocolType::ipmbV10}, 133 {"icmb-2.0", EChannelProtocolType::icmbV11}, 134 {"reserved", EChannelProtocolType::reserved}, 135 {"ipmi-smbus", EChannelProtocolType::ipmiSmbus}, 136 {"kcs", EChannelProtocolType::kcs}, 137 {"smic", EChannelProtocolType::smic}, 138 {"bt-10", EChannelProtocolType::bt10}, 139 {"bt-15", EChannelProtocolType::bt15}, 140 {"tmode", EChannelProtocolType::tMode}, 141 {"oem", EChannelProtocolType::oem}}; 142 143 static std::array<std::string, 4> accessModeList = { 144 "disabled", "pre-boot", "always_available", "shared"}; 145 146 static std::array<std::string, 4> sessionSupportList = { 147 "session-less", "single-session", "multi-session", "session-based"}; 148 149 const std::array<std::string, PRIVILEGE_OEM + 1> privList = { 150 "priv-reserved", "priv-callback", "priv-user", 151 "priv-operator", "priv-admin", "priv-oem"}; 152 153 std::string ChannelConfig::getChannelName(const uint8_t chNum) 154 { 155 if (!isValidChannel(chNum)) 156 { 157 log<level::ERR>("Invalid channel number.", 158 entry("CHANNEL_ID=%d", chNum)); 159 throw std::invalid_argument("Invalid channel number"); 160 } 161 162 return channelData[chNum].chName; 163 } 164 165 int ChannelConfig::convertToChannelNumberFromChannelName( 166 const std::string& chName) 167 { 168 for (const auto& it : channelData) 169 { 170 if (it.chName == chName) 171 { 172 return it.chID; 173 } 174 } 175 log<level::ERR>("Invalid channel name.", 176 entry("CHANNEL=%s", chName.c_str())); 177 throw std::invalid_argument("Invalid channel name"); 178 179 return -1; 180 } 181 182 std::string ChannelConfig::getChannelNameFromPath(const std::string& path) 183 { 184 const size_t length = strlen(networkIntfObjectBasePath); 185 if (((length + 1) >= path.size()) || 186 path.compare(0, length, networkIntfObjectBasePath)) 187 { 188 log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str())); 189 throw std::invalid_argument("Invalid object path"); 190 } 191 std::string chName(path, length + 1); 192 return chName; 193 } 194 195 void ChannelConfig::processChAccessPropChange( 196 const std::string& path, const DbusChObjProperties& chProperties) 197 { 198 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0' 199 std::string chName; 200 try 201 { 202 chName = getChannelNameFromPath(path); 203 } 204 catch (const std::invalid_argument& e) 205 { 206 log<level::ERR>("Exception: ", entry("MSG=%s", e.what())); 207 return; 208 } 209 210 // Get the MaxPrivilege property value from the signal 211 std::string intfPrivStr; 212 std::string propName; 213 for (const auto& prop : chProperties) 214 { 215 if (prop.first == privilegePropertyString) 216 { 217 propName = privilegePropertyString; 218 intfPrivStr = std::get<std::string>(prop.second); 219 break; 220 } 221 } 222 223 if (propName != privilegePropertyString) 224 { 225 log<level::ERR>("Unknown signal caught."); 226 return; 227 } 228 229 if (intfPrivStr.empty()) 230 { 231 log<level::ERR>("Invalid privilege string.", 232 entry("INTF=%s", chName.c_str())); 233 return; 234 } 235 236 uint8_t intfPriv = 0; 237 int chNum; 238 try 239 { 240 intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr)); 241 chNum = convertToChannelNumberFromChannelName(chName); 242 } 243 catch (const std::invalid_argument& e) 244 { 245 log<level::ERR>("Exception: ", entry("MSG=%s", e.what())); 246 return; 247 } 248 249 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 250 channelLock{*channelMutex}; 251 // skip updating the values, if this property change originated from IPMI. 252 if (signalFlag & (1 << chNum)) 253 { 254 signalFlag &= ~(1 << chNum); 255 log<level::DEBUG>("Request originated from IPMI so ignoring signal"); 256 return; 257 } 258 259 // Update both volatile & Non-volatile, if there is mismatch. 260 // as property change other than IPMI, has to update both volatile & 261 // non-volatile data. 262 checkAndReloadVolatileData(); 263 checkAndReloadNVData(); 264 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv) 265 { 266 // Update NV data 267 channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv; 268 if (writeChannelPersistData() != 0) 269 { 270 log<level::ERR>("Failed to update the persist data file"); 271 return; 272 } 273 274 // Update Volatile data 275 if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv) 276 { 277 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv; 278 if (writeChannelVolatileData() != 0) 279 { 280 log<level::ERR>("Failed to update the volatile data file"); 281 return; 282 } 283 } 284 } 285 286 return; 287 } 288 289 ChannelConfig& getChannelConfigObject() 290 { 291 static ChannelConfig channelConfig; 292 return channelConfig; 293 } 294 295 ChannelConfig::~ChannelConfig() 296 { 297 if (signalHndlrObjectState) 298 { 299 chPropertiesSignal.reset(); 300 chInterfaceAddedSignal.reset(); 301 chInterfaceRemovedSignal.reset(); 302 sigHndlrLock.unlock(); 303 } 304 } 305 306 ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection()) 307 { 308 std::ofstream mutexCleanUpFile; 309 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile, 310 std::ofstream::out | std::ofstream::app); 311 if (!mutexCleanUpFile.good()) 312 { 313 log<level::DEBUG>("Unable to open mutex cleanup file"); 314 return; 315 } 316 mutexCleanUpFile.close(); 317 mutexCleanupLock = 318 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile); 319 if (mutexCleanupLock.try_lock()) 320 { 321 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex); 322 channelMutex = 323 std::make_unique<boost::interprocess::named_recursive_mutex>( 324 boost::interprocess::open_or_create, ipmiChannelMutex); 325 mutexCleanupLock.lock_sharable(); 326 } 327 else 328 { 329 mutexCleanupLock.lock_sharable(); 330 channelMutex = 331 std::make_unique<boost::interprocess::named_recursive_mutex>( 332 boost::interprocess::open_or_create, ipmiChannelMutex); 333 } 334 335 initChannelPersistData(); 336 337 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename); 338 // Register it for single object and single process either netipmid / 339 // host-ipmid 340 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock()) 341 { 342 log<level::DEBUG>("Registering channel signal handler."); 343 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 344 bus, 345 sdbusplus::bus::match::rules::path_namespace( 346 networkIntfObjectBasePath) + 347 sdbusplus::bus::match::rules::type::signal() + 348 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 349 sdbusplus::bus::match::rules::interface( 350 dBusPropertiesInterface) + 351 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName), 352 [&](sdbusplus::message_t& msg) { 353 DbusChObjProperties props; 354 std::string iface; 355 std::string path = msg.get_path(); 356 msg.read(iface, props); 357 processChAccessPropChange(path, props); 358 }); 359 signalHndlrObjectState = true; 360 361 chInterfaceAddedSignal = std::make_unique<sdbusplus::bus::match_t>( 362 bus, 363 sdbusplus::bus::match::rules::type::signal() + 364 sdbusplus::bus::match::rules::member(interfaceAddedSignal) + 365 sdbusplus::bus::match::rules::argNpath( 366 0, std::string(networkIntfObjectBasePath) + "/"), 367 [&](sdbusplus::message_t&) { initChannelPersistData(); }); 368 369 chInterfaceRemovedSignal = std::make_unique<sdbusplus::bus::match_t>( 370 bus, 371 sdbusplus::bus::match::rules::type::signal() + 372 sdbusplus::bus::match::rules::member(interfaceRemovedSignal) + 373 sdbusplus::bus::match::rules::argNpath( 374 0, std::string(networkIntfObjectBasePath) + "/"), 375 [&](sdbusplus::message_t&) { initChannelPersistData(); }); 376 } 377 } 378 379 bool ChannelConfig::isValidChannel(const uint8_t chNum) 380 { 381 if (chNum >= maxIpmiChannels) 382 { 383 log<level::DEBUG>("Invalid channel ID - Out of range"); 384 return false; 385 } 386 387 if (channelData[chNum].isChValid == false) 388 { 389 log<level::DEBUG>("Channel is not valid"); 390 } 391 392 return channelData[chNum].isChValid; 393 } 394 395 EChannelSessSupported 396 ChannelConfig::getChannelSessionSupport(const uint8_t chNum) 397 { 398 EChannelSessSupported chSessSupport = 399 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported; 400 return chSessSupport; 401 } 402 403 bool ChannelConfig::isValidAuthType(const uint8_t chNum, 404 const EAuthType& authType) 405 { 406 if ((authType < EAuthType::md2) || (authType > EAuthType::oem)) 407 { 408 log<level::DEBUG>("Invalid authentication type"); 409 return false; 410 } 411 412 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported; 413 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType)))) 414 { 415 log<level::DEBUG>("Authentication type is not supported."); 416 return false; 417 } 418 419 return true; 420 } 421 422 int ChannelConfig::getChannelActiveSessions(const uint8_t chNum) 423 { 424 // TODO: TEMPORARY FIX 425 // Channels active session count is managed separately 426 // by monitoring channel session which includes LAN and 427 // RAKP layer changes. This will be updated, once the 428 // authentication part is implemented. 429 return channelData[chNum].activeSessCount; 430 } 431 432 size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum) 433 { 434 return channelData[chNum].maxTransferSize; 435 } 436 437 Cc ChannelConfig::getChannelInfo(const uint8_t chNum, ChannelInfo& chInfo) 438 { 439 if (!isValidChannel(chNum)) 440 { 441 log<level::DEBUG>("Invalid channel"); 442 return ccInvalidFieldRequest; 443 } 444 445 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo), 446 sizeof(channelData[chNum].chInfo), 447 reinterpret_cast<uint8_t*>(&chInfo)); 448 return ccSuccess; 449 } 450 451 Cc ChannelConfig::getChannelAccessData(const uint8_t chNum, 452 ChannelAccess& chAccessData) 453 { 454 if (!isValidChannel(chNum)) 455 { 456 log<level::DEBUG>("Invalid channel"); 457 return ccInvalidFieldRequest; 458 } 459 460 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 461 { 462 log<level::DEBUG>("Session-less channel doesn't have access data."); 463 return ccActionNotSupportedForChannel; 464 } 465 466 if (checkAndReloadVolatileData() != 0) 467 { 468 return ccUnspecifiedError; 469 } 470 471 std::copy_n( 472 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData), 473 sizeof(channelData[chNum].chAccess.chVolatileData), 474 reinterpret_cast<uint8_t*>(&chAccessData)); 475 476 return ccSuccess; 477 } 478 479 Cc ChannelConfig::setChannelAccessData(const uint8_t chNum, 480 const ChannelAccess& chAccessData, 481 const uint8_t setFlag) 482 { 483 if (!isValidChannel(chNum)) 484 { 485 log<level::DEBUG>("Invalid channel"); 486 return ccInvalidFieldRequest; 487 } 488 489 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 490 { 491 log<level::DEBUG>("Session-less channel doesn't have access data."); 492 return ccActionNotSupportedForChannel; 493 } 494 495 if ((setFlag & setAccessMode) && 496 (!isValidAccessMode(chAccessData.accessMode))) 497 { 498 log<level::DEBUG>("Invalid access mode specified"); 499 return ccAccessModeNotSupportedForChannel; 500 } 501 if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit))) 502 { 503 log<level::DEBUG>("Invalid privilege limit specified"); 504 return ccInvalidFieldRequest; 505 } 506 507 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 508 channelLock{*channelMutex}; 509 510 if (checkAndReloadVolatileData() != 0) 511 { 512 return ccUnspecifiedError; 513 } 514 515 if (setFlag & setAccessMode) 516 { 517 channelData[chNum].chAccess.chVolatileData.accessMode = 518 chAccessData.accessMode; 519 } 520 if (setFlag & setUserAuthEnabled) 521 { 522 channelData[chNum].chAccess.chVolatileData.userAuthDisabled = 523 chAccessData.userAuthDisabled; 524 } 525 if (setFlag & setMsgAuthEnabled) 526 { 527 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled = 528 chAccessData.perMsgAuthDisabled; 529 } 530 if (setFlag & setAlertingEnabled) 531 { 532 channelData[chNum].chAccess.chVolatileData.alertingDisabled = 533 chAccessData.alertingDisabled; 534 } 535 if (setFlag & setPrivLimit) 536 { 537 channelData[chNum].chAccess.chVolatileData.privLimit = 538 chAccessData.privLimit; 539 } 540 541 // Write Volatile data to file 542 if (writeChannelVolatileData() != 0) 543 { 544 log<level::DEBUG>("Failed to update the channel volatile data"); 545 return ccUnspecifiedError; 546 } 547 return ccSuccess; 548 } 549 550 Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum, 551 ChannelAccess& chAccessData) 552 { 553 if (!isValidChannel(chNum)) 554 { 555 log<level::DEBUG>("Invalid channel"); 556 return ccInvalidFieldRequest; 557 } 558 559 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 560 { 561 log<level::DEBUG>("Session-less channel doesn't have access data."); 562 return ccActionNotSupportedForChannel; 563 } 564 565 if (checkAndReloadNVData() != 0) 566 { 567 return ccUnspecifiedError; 568 } 569 570 std::copy_n(reinterpret_cast<uint8_t*>( 571 &channelData[chNum].chAccess.chNonVolatileData), 572 sizeof(channelData[chNum].chAccess.chNonVolatileData), 573 reinterpret_cast<uint8_t*>(&chAccessData)); 574 575 return ccSuccess; 576 } 577 578 Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum, 579 const ChannelAccess& chAccessData, 580 const uint8_t setFlag) 581 { 582 if (!isValidChannel(chNum)) 583 { 584 log<level::DEBUG>("Invalid channel"); 585 return ccInvalidFieldRequest; 586 } 587 588 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 589 { 590 log<level::DEBUG>("Session-less channel doesn't have access data."); 591 return ccActionNotSupportedForChannel; 592 } 593 594 if ((setFlag & setAccessMode) && 595 (!isValidAccessMode(chAccessData.accessMode))) 596 { 597 log<level::DEBUG>("Invalid access mode specified"); 598 return ccAccessModeNotSupportedForChannel; 599 } 600 if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit))) 601 { 602 log<level::DEBUG>("Invalid privilege limit specified"); 603 return ccInvalidFieldRequest; 604 } 605 606 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 607 channelLock{*channelMutex}; 608 609 if (checkAndReloadNVData() != 0) 610 { 611 return ccUnspecifiedError; 612 } 613 614 if (setFlag & setAccessMode) 615 { 616 channelData[chNum].chAccess.chNonVolatileData.accessMode = 617 chAccessData.accessMode; 618 } 619 if (setFlag & setUserAuthEnabled) 620 { 621 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled = 622 chAccessData.userAuthDisabled; 623 } 624 if (setFlag & setMsgAuthEnabled) 625 { 626 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled = 627 chAccessData.perMsgAuthDisabled; 628 } 629 if (setFlag & setAlertingEnabled) 630 { 631 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled = 632 chAccessData.alertingDisabled; 633 } 634 if (setFlag & setPrivLimit) 635 { 636 // Send Update to network channel config interfaces over dbus 637 std::string privStr = convertToPrivLimitString(chAccessData.privLimit); 638 std::string networkIntfObj = std::string(networkIntfObjectBasePath) + 639 "/" + channelData[chNum].chName; 640 try 641 { 642 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj, 643 networkChConfigIntfName, 644 privilegePropertyString, privStr)) 645 { 646 log<level::DEBUG>( 647 "Network interface does not exist", 648 entry("INTERFACE=%s", channelData[chNum].chName.c_str())); 649 return ccUnspecifiedError; 650 } 651 } 652 catch (const sdbusplus::exception_t& e) 653 { 654 log<level::ERR>("Exception: Network interface does not exist"); 655 return ccInvalidFieldRequest; 656 } 657 signalFlag |= (1 << chNum); 658 channelData[chNum].chAccess.chNonVolatileData.privLimit = 659 chAccessData.privLimit; 660 } 661 662 // Write persistent data to file 663 if (writeChannelPersistData() != 0) 664 { 665 log<level::DEBUG>("Failed to update the presist data file"); 666 return ccUnspecifiedError; 667 } 668 return ccSuccess; 669 } 670 671 Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum, 672 uint8_t& authTypeSupported) 673 { 674 if (!isValidChannel(chNum)) 675 { 676 log<level::DEBUG>("Invalid channel"); 677 return ccInvalidFieldRequest; 678 } 679 680 authTypeSupported = channelData[chNum].chInfo.authTypeSupported; 681 return ccSuccess; 682 } 683 684 Cc ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum, 685 const uint8_t priv, 686 EAuthType& authType) 687 { 688 if (!isValidChannel(chNum)) 689 { 690 log<level::DEBUG>("Invalid channel"); 691 return ccInvalidFieldRequest; 692 } 693 694 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 695 { 696 log<level::DEBUG>("Sessionless channel doesn't have access data."); 697 return ccInvalidFieldRequest; 698 } 699 700 if (!isValidPrivLimit(priv)) 701 { 702 log<level::DEBUG>("Invalid privilege specified."); 703 return ccInvalidFieldRequest; 704 } 705 706 // TODO: Hardcoded for now. Need to implement. 707 authType = EAuthType::none; 708 709 return ccSuccess; 710 } 711 712 std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName) 713 { 714 struct stat fileStat; 715 if (stat(fileName.c_str(), &fileStat) != 0) 716 { 717 log<level::DEBUG>("Error in getting last updated time stamp"); 718 return -EIO; 719 } 720 return fileStat.st_mtime; 721 } 722 723 EChannelAccessMode 724 ChannelConfig::convertToAccessModeIndex(const std::string& mode) 725 { 726 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode); 727 if (iter == accessModeList.end()) 728 { 729 log<level::ERR>("Invalid access mode.", 730 entry("MODE_STR=%s", mode.c_str())); 731 throw std::invalid_argument("Invalid access mode."); 732 } 733 734 return static_cast<EChannelAccessMode>( 735 std::distance(accessModeList.begin(), iter)); 736 } 737 738 std::string ChannelConfig::convertToAccessModeString(const uint8_t value) 739 { 740 if (accessModeList.size() <= value) 741 { 742 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value)); 743 throw std::invalid_argument("Invalid access mode."); 744 } 745 746 return accessModeList.at(value); 747 } 748 749 CommandPrivilege 750 ChannelConfig::convertToPrivLimitIndex(const std::string& value) 751 { 752 auto iter = std::find(privList.begin(), privList.end(), value); 753 if (iter == privList.end()) 754 { 755 log<level::ERR>("Invalid privilege.", 756 entry("PRIV_STR=%s", value.c_str())); 757 throw std::invalid_argument("Invalid privilege."); 758 } 759 760 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter)); 761 } 762 763 std::string ChannelConfig::convertToPrivLimitString(const uint8_t value) 764 { 765 if (privList.size() <= value) 766 { 767 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value)); 768 throw std::invalid_argument("Invalid privilege."); 769 } 770 771 return privList.at(value); 772 } 773 774 EChannelSessSupported 775 ChannelConfig::convertToSessionSupportIndex(const std::string& value) 776 { 777 auto iter = std::find(sessionSupportList.begin(), sessionSupportList.end(), 778 value); 779 if (iter == sessionSupportList.end()) 780 { 781 log<level::ERR>("Invalid session supported.", 782 entry("SESS_STR=%s", value.c_str())); 783 throw std::invalid_argument("Invalid session supported."); 784 } 785 786 return static_cast<EChannelSessSupported>( 787 std::distance(sessionSupportList.begin(), iter)); 788 } 789 790 EChannelMediumType 791 ChannelConfig::convertToMediumTypeIndex(const std::string& value) 792 { 793 std::unordered_map<std::string, EChannelMediumType>::iterator it = 794 mediumTypeMap.find(value); 795 if (it == mediumTypeMap.end()) 796 { 797 log<level::ERR>("Invalid medium type.", 798 entry("MEDIUM_STR=%s", value.c_str())); 799 throw std::invalid_argument("Invalid medium type."); 800 } 801 802 return static_cast<EChannelMediumType>(it->second); 803 } 804 805 EChannelProtocolType 806 ChannelConfig::convertToProtocolTypeIndex(const std::string& value) 807 { 808 std::unordered_map<std::string, EChannelProtocolType>::iterator it = 809 protocolTypeMap.find(value); 810 if (it == protocolTypeMap.end()) 811 { 812 log<level::ERR>("Invalid protocol type.", 813 entry("PROTO_STR=%s", value.c_str())); 814 throw std::invalid_argument("Invalid protocol type."); 815 } 816 817 return static_cast<EChannelProtocolType>(it->second); 818 } 819 820 Json ChannelConfig::readJsonFile(const std::string& configFile) 821 { 822 std::ifstream jsonFile(configFile); 823 if (!jsonFile.good()) 824 { 825 log<level::INFO>("JSON file not found", 826 entry("FILE_NAME=%s", configFile.c_str())); 827 return nullptr; 828 } 829 830 Json data = nullptr; 831 try 832 { 833 data = Json::parse(jsonFile, nullptr, false); 834 } 835 catch (const Json::parse_error& e) 836 { 837 log<level::DEBUG>("Corrupted channel config.", 838 entry("MSG=%s", e.what())); 839 throw std::runtime_error("Corrupted channel config file"); 840 } 841 842 return data; 843 } 844 845 int ChannelConfig::writeJsonFile(const std::string& configFile, 846 const Json& jsonData) 847 { 848 const std::string tmpFile = configFile + "_tmp"; 849 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 850 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 851 if (fd < 0) 852 { 853 log<level::ERR>("Error in creating json file", 854 entry("FILE_NAME = %s", tmpFile.c_str())); 855 return -EIO; 856 } 857 const auto& writeData = jsonData.dump(); 858 if (write(fd, writeData.c_str(), writeData.size()) != 859 static_cast<ssize_t>(writeData.size())) 860 { 861 close(fd); 862 log<level::ERR>("Error in writing configuration file", 863 entry("FILE_NAME = %s", tmpFile.c_str())); 864 return -EIO; 865 } 866 close(fd); 867 868 if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0) 869 { 870 log<level::ERR>("Error in renaming temporary data file", 871 entry("FILE_NAME = %s", tmpFile.c_str())); 872 return -EIO; 873 } 874 875 return 0; 876 } 877 878 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum, 879 const std::string& chName) 880 { 881 channelData[chNum].chName = chName; 882 channelData[chNum].chID = chNum; 883 channelData[chNum].isChValid = false; 884 channelData[chNum].activeSessCount = 0; 885 channelData[chNum].isManagementNIC = false; 886 887 channelData[chNum].chInfo.mediumType = defaultMediumType; 888 channelData[chNum].chInfo.protocolType = defaultProtocolType; 889 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported; 890 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState; 891 channelData[chNum].chInfo.authTypeSupported = defaultAuthType; 892 } 893 894 uint8_t ChannelConfig::getManagementNICID() 895 { 896 static bool idFound = false; 897 static uint8_t id = 0; 898 899 if (idFound) 900 { 901 return id; 902 } 903 904 for (uint8_t chIdx = 0; chIdx < maxIpmiChannels; chIdx++) 905 { 906 if (channelData[chIdx].isManagementNIC) 907 { 908 id = chIdx; 909 idFound = true; 910 break; 911 } 912 } 913 914 if (!idFound) 915 { 916 id = static_cast<uint8_t>(EChannelID::chanLan1); 917 idFound = true; 918 } 919 return id; 920 } 921 922 int ChannelConfig::loadChannelConfig() 923 { 924 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 925 channelLock{*channelMutex}; 926 927 Json data = readJsonFile(channelConfigDefaultFilename); 928 if (data.empty()) 929 { 930 log<level::DEBUG>("Error in opening IPMI Channel data file"); 931 return -EIO; 932 } 933 934 channelData.fill(ChannelProperties{}); 935 936 // Collect the list of NIC interfaces connected to the BMC. Use this 937 // information to only add IPMI channels that have active NIC interfaces. 938 struct ifaddrs *ifaddr = nullptr, *ifa = nullptr; 939 if (int err = getifaddrs(&ifaddr); err < 0) 940 { 941 log<level::DEBUG>("Unable to acquire network interfaces"); 942 return -EIO; 943 } 944 945 for (int chNum = 0; chNum < maxIpmiChannels; chNum++) 946 { 947 try 948 { 949 std::string chKey = std::to_string(chNum); 950 Json jsonChData = data[chKey].get<Json>(); 951 if (jsonChData.is_null()) 952 { 953 // If user didn't want to configure specific channel (say 954 // reserved channel), then load that index with default values. 955 setDefaultChannelConfig(chNum, defaultChannelName); 956 continue; 957 } 958 Json jsonChInfo = jsonChData[channelInfoString].get<Json>(); 959 if (jsonChInfo.is_null()) 960 { 961 log<level::ERR>("Invalid/corrupted channel config file"); 962 freeifaddrs(ifaddr); 963 return -EBADMSG; 964 } 965 966 bool channelFound = true; 967 // Confirm the LAN channel is present 968 if (jsonChInfo[mediumTypeString].get<std::string>() == "lan-802.3") 969 { 970 channelFound = false; 971 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 972 { 973 if (jsonChData[nameString].get<std::string>() == 974 ifa->ifa_name) 975 { 976 channelFound = true; 977 break; 978 } 979 } 980 } 981 ChannelProperties& chData = channelData[chNum]; 982 chData.chID = chNum; 983 chData.chName = jsonChData[nameString].get<std::string>(); 984 chData.isChValid = channelFound && 985 jsonChData[isValidString].get<bool>(); 986 chData.activeSessCount = jsonChData.value(activeSessionsString, 0); 987 chData.maxTransferSize = jsonChData.value(maxTransferSizeString, 988 smallChannelSize); 989 if (jsonChData.count(isManagementNIC) != 0) 990 { 991 chData.isManagementNIC = 992 jsonChData[isManagementNIC].get<bool>(); 993 } 994 995 std::string medTypeStr = 996 jsonChInfo[mediumTypeString].get<std::string>(); 997 chData.chInfo.mediumType = 998 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr)); 999 std::string protoTypeStr = 1000 jsonChInfo[protocolTypeString].get<std::string>(); 1001 chData.chInfo.protocolType = 1002 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr)); 1003 std::string sessStr = 1004 jsonChInfo[sessionSupportedString].get<std::string>(); 1005 chData.chInfo.sessionSupported = 1006 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr)); 1007 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>(); 1008 chData.chInfo.authTypeSupported = defaultAuthType; 1009 } 1010 catch (const Json::exception& e) 1011 { 1012 log<level::DEBUG>("Json Exception caught.", 1013 entry("MSG=%s", e.what())); 1014 freeifaddrs(ifaddr); 1015 1016 return -EBADMSG; 1017 } 1018 catch (const std::invalid_argument& e) 1019 { 1020 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what())); 1021 freeifaddrs(ifaddr); 1022 return -EBADMSG; 1023 } 1024 } 1025 freeifaddrs(ifaddr); 1026 1027 return 0; 1028 } 1029 1030 int ChannelConfig::readChannelVolatileData() 1031 { 1032 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1033 channelLock{*channelMutex}; 1034 1035 Json data = readJsonFile(channelVolatileDataFilename); 1036 if (data == nullptr) 1037 { 1038 log<level::DEBUG>("Error in opening IPMI Channel data file"); 1039 return -EIO; 1040 } 1041 try 1042 { 1043 // Fill in global structure 1044 for (auto it = data.begin(); it != data.end(); ++it) 1045 { 1046 std::string chKey = it.key(); 1047 uint8_t chNum = std::stoi(chKey, nullptr, 10); 1048 if (chNum >= maxIpmiChannels) 1049 { 1050 log<level::DEBUG>( 1051 "Invalid channel access entry in config file"); 1052 throw std::out_of_range("Out of range - channel number"); 1053 } 1054 Json jsonChData = it.value(); 1055 if (!jsonChData.is_null()) 1056 { 1057 std::string accModeStr = 1058 jsonChData[accessModeString].get<std::string>(); 1059 channelData[chNum].chAccess.chVolatileData.accessMode = 1060 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr)); 1061 channelData[chNum].chAccess.chVolatileData.userAuthDisabled = 1062 jsonChData[userAuthDisabledString].get<bool>(); 1063 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled = 1064 jsonChData[perMsgAuthDisabledString].get<bool>(); 1065 channelData[chNum].chAccess.chVolatileData.alertingDisabled = 1066 jsonChData[alertingDisabledString].get<bool>(); 1067 std::string privStr = 1068 jsonChData[privLimitString].get<std::string>(); 1069 channelData[chNum].chAccess.chVolatileData.privLimit = 1070 static_cast<uint8_t>(convertToPrivLimitIndex(privStr)); 1071 } 1072 else 1073 { 1074 log<level::ERR>( 1075 "Invalid/corrupted volatile channel access file", 1076 entry("FILE=%s", channelVolatileDataFilename)); 1077 throw std::runtime_error( 1078 "Corrupted volatile channel access file"); 1079 } 1080 } 1081 } 1082 catch (const Json::exception& e) 1083 { 1084 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what())); 1085 throw std::runtime_error("Corrupted volatile channel access file"); 1086 } 1087 catch (const std::invalid_argument& e) 1088 { 1089 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what())); 1090 throw std::runtime_error("Corrupted volatile channel access file"); 1091 } 1092 1093 // Update the timestamp 1094 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename); 1095 return 0; 1096 } 1097 1098 int ChannelConfig::readChannelPersistData() 1099 { 1100 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1101 channelLock{*channelMutex}; 1102 1103 Json data = readJsonFile(channelNvDataFilename); 1104 if (data == nullptr) 1105 { 1106 log<level::DEBUG>("Error in opening IPMI Channel data file"); 1107 return -EIO; 1108 } 1109 try 1110 { 1111 // Fill in global structure 1112 for (auto it = data.begin(); it != data.end(); ++it) 1113 { 1114 std::string chKey = it.key(); 1115 uint8_t chNum = std::stoi(chKey, nullptr, 10); 1116 if (chNum >= maxIpmiChannels) 1117 { 1118 log<level::DEBUG>( 1119 "Invalid channel access entry in config file"); 1120 throw std::out_of_range("Out of range - channel number"); 1121 } 1122 Json jsonChData = it.value(); 1123 if (!jsonChData.is_null()) 1124 { 1125 std::string accModeStr = 1126 jsonChData[accessModeString].get<std::string>(); 1127 channelData[chNum].chAccess.chNonVolatileData.accessMode = 1128 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr)); 1129 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled = 1130 jsonChData[userAuthDisabledString].get<bool>(); 1131 channelData[chNum] 1132 .chAccess.chNonVolatileData.perMsgAuthDisabled = 1133 jsonChData[perMsgAuthDisabledString].get<bool>(); 1134 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled = 1135 jsonChData[alertingDisabledString].get<bool>(); 1136 std::string privStr = 1137 jsonChData[privLimitString].get<std::string>(); 1138 channelData[chNum].chAccess.chNonVolatileData.privLimit = 1139 static_cast<uint8_t>(convertToPrivLimitIndex(privStr)); 1140 } 1141 else 1142 { 1143 log<level::ERR>("Invalid/corrupted nv channel access file", 1144 entry("FILE=%s", channelNvDataFilename)); 1145 throw std::runtime_error("Corrupted nv channel access file"); 1146 } 1147 } 1148 } 1149 catch (const Json::exception& e) 1150 { 1151 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what())); 1152 throw std::runtime_error("Corrupted nv channel access file"); 1153 } 1154 catch (const std::invalid_argument& e) 1155 { 1156 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what())); 1157 throw std::runtime_error("Corrupted nv channel access file"); 1158 } 1159 1160 // Update the timestamp 1161 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename); 1162 return 0; 1163 } 1164 1165 int ChannelConfig::writeChannelVolatileData() 1166 { 1167 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1168 channelLock{*channelMutex}; 1169 Json outData; 1170 1171 try 1172 { 1173 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1174 { 1175 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1176 { 1177 Json jsonObj; 1178 std::string chKey = std::to_string(chNum); 1179 std::string accModeStr = convertToAccessModeString( 1180 channelData[chNum].chAccess.chVolatileData.accessMode); 1181 jsonObj[accessModeString] = accModeStr; 1182 jsonObj[userAuthDisabledString] = 1183 channelData[chNum].chAccess.chVolatileData.userAuthDisabled; 1184 jsonObj[perMsgAuthDisabledString] = 1185 channelData[chNum] 1186 .chAccess.chVolatileData.perMsgAuthDisabled; 1187 jsonObj[alertingDisabledString] = 1188 channelData[chNum].chAccess.chVolatileData.alertingDisabled; 1189 std::string privStr = convertToPrivLimitString( 1190 channelData[chNum].chAccess.chVolatileData.privLimit); 1191 jsonObj[privLimitString] = privStr; 1192 1193 outData[chKey] = jsonObj; 1194 } 1195 } 1196 } 1197 catch (const std::invalid_argument& e) 1198 { 1199 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what())); 1200 return -EINVAL; 1201 } 1202 1203 if (writeJsonFile(channelVolatileDataFilename, outData) != 0) 1204 { 1205 log<level::DEBUG>("Error in write JSON data to file"); 1206 return -EIO; 1207 } 1208 1209 // Update the timestamp 1210 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename); 1211 return 0; 1212 } 1213 1214 int ChannelConfig::writeChannelPersistData() 1215 { 1216 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1217 channelLock{*channelMutex}; 1218 Json outData; 1219 1220 try 1221 { 1222 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1223 { 1224 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1225 { 1226 Json jsonObj; 1227 std::string chKey = std::to_string(chNum); 1228 std::string accModeStr = convertToAccessModeString( 1229 channelData[chNum].chAccess.chNonVolatileData.accessMode); 1230 jsonObj[accessModeString] = accModeStr; 1231 jsonObj[userAuthDisabledString] = 1232 channelData[chNum] 1233 .chAccess.chNonVolatileData.userAuthDisabled; 1234 jsonObj[perMsgAuthDisabledString] = 1235 channelData[chNum] 1236 .chAccess.chNonVolatileData.perMsgAuthDisabled; 1237 jsonObj[alertingDisabledString] = 1238 channelData[chNum] 1239 .chAccess.chNonVolatileData.alertingDisabled; 1240 std::string privStr = convertToPrivLimitString( 1241 channelData[chNum].chAccess.chNonVolatileData.privLimit); 1242 jsonObj[privLimitString] = privStr; 1243 1244 outData[chKey] = jsonObj; 1245 } 1246 } 1247 } 1248 catch (const std::invalid_argument& e) 1249 { 1250 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what())); 1251 return -EINVAL; 1252 } 1253 1254 if (writeJsonFile(channelNvDataFilename, outData) != 0) 1255 { 1256 log<level::DEBUG>("Error in write JSON data to file"); 1257 return -EIO; 1258 } 1259 1260 // Update the timestamp 1261 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename); 1262 return 0; 1263 } 1264 1265 int ChannelConfig::checkAndReloadNVData() 1266 { 1267 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename); 1268 int ret = 0; 1269 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO) 1270 { 1271 try 1272 { 1273 ret = readChannelPersistData(); 1274 } 1275 catch (const std::exception& e) 1276 { 1277 log<level::ERR>("Exception caught in readChannelPersistData.", 1278 entry("MSG=%s", e.what())); 1279 ret = -EIO; 1280 } 1281 } 1282 return ret; 1283 } 1284 1285 int ChannelConfig::checkAndReloadVolatileData() 1286 { 1287 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename); 1288 int ret = 0; 1289 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO) 1290 { 1291 try 1292 { 1293 ret = readChannelVolatileData(); 1294 } 1295 catch (const std::exception& e) 1296 { 1297 log<level::ERR>("Exception caught in readChannelVolatileData.", 1298 entry("MSG=%s", e.what())); 1299 ret = -EIO; 1300 } 1301 } 1302 return ret; 1303 } 1304 1305 int ChannelConfig::setDbusProperty(const std::string& service, 1306 const std::string& objPath, 1307 const std::string& interface, 1308 const std::string& property, 1309 const DbusVariant& value) 1310 { 1311 try 1312 { 1313 auto method = bus.new_method_call(service.c_str(), objPath.c_str(), 1314 "org.freedesktop.DBus.Properties", 1315 "Set"); 1316 1317 method.append(interface, property, value); 1318 1319 auto reply = bus.call(method); 1320 } 1321 catch (const sdbusplus::exception_t& e) 1322 { 1323 log<level::DEBUG>("set-property failed", 1324 entry("SERVICE=%s", service.c_str()), 1325 entry("OBJPATH=%s", objPath.c_str()), 1326 entry("INTERFACE=%s", interface.c_str()), 1327 entry("PROP=%s", property.c_str())); 1328 return -EIO; 1329 } 1330 1331 return 0; 1332 } 1333 1334 int ChannelConfig::getDbusProperty(const std::string& service, 1335 const std::string& objPath, 1336 const std::string& interface, 1337 const std::string& property, 1338 DbusVariant& value) 1339 { 1340 try 1341 { 1342 auto method = bus.new_method_call(service.c_str(), objPath.c_str(), 1343 "org.freedesktop.DBus.Properties", 1344 "Get"); 1345 1346 method.append(interface, property); 1347 1348 auto reply = bus.call(method); 1349 reply.read(value); 1350 } 1351 catch (const sdbusplus::exception_t& e) 1352 { 1353 log<level::DEBUG>("get-property failed", 1354 entry("SERVICE=%s", service.c_str()), 1355 entry("OBJPATH=%s", objPath.c_str()), 1356 entry("INTERFACE=%s", interface.c_str()), 1357 entry("PROP=%s", property.c_str())); 1358 return -EIO; 1359 } 1360 return 0; 1361 } 1362 1363 int ChannelConfig::syncNetworkChannelConfig() 1364 { 1365 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1366 channelLock{*channelMutex}; 1367 bool isUpdated = false; 1368 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1369 { 1370 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1371 { 1372 std::string intfPrivStr; 1373 uint8_t intfPriv = 0; 1374 try 1375 { 1376 std::string networkIntfObj = 1377 std::string(networkIntfObjectBasePath) + "/" + 1378 channelData[chNum].chName; 1379 DbusVariant variant; 1380 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj, 1381 networkChConfigIntfName, 1382 privilegePropertyString, variant)) 1383 { 1384 log<level::DEBUG>("Network interface does not exist", 1385 entry("INTERFACE=%s", 1386 channelData[chNum].chName.c_str())); 1387 continue; 1388 } 1389 intfPrivStr = std::get<std::string>(variant); 1390 intfPriv = 1391 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr)); 1392 } 1393 catch (const std::bad_variant_access& e) 1394 { 1395 log<level::DEBUG>( 1396 "exception: Network interface does not exist"); 1397 continue; 1398 } 1399 catch (const sdbusplus::exception_t& e) 1400 { 1401 log<level::DEBUG>( 1402 "exception: Network interface does not exist"); 1403 continue; 1404 } 1405 catch (const std::invalid_argument& e) 1406 { 1407 log<level::DEBUG>("exception: Invalid privilege"); 1408 continue; 1409 } 1410 1411 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != 1412 intfPriv) 1413 { 1414 isUpdated = true; 1415 channelData[chNum].chAccess.chNonVolatileData.privLimit = 1416 intfPriv; 1417 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv; 1418 } 1419 } 1420 } 1421 1422 if (isUpdated) 1423 { 1424 // Write persistent data to file 1425 if (writeChannelPersistData() != 0) 1426 { 1427 log<level::DEBUG>("Failed to update the persistent data file"); 1428 return -EIO; 1429 } 1430 // Write Volatile data to file 1431 if (writeChannelVolatileData() != 0) 1432 { 1433 log<level::DEBUG>("Failed to update the channel volatile data"); 1434 return -EIO; 1435 } 1436 } 1437 1438 return 0; 1439 } 1440 1441 void ChannelConfig::initChannelPersistData() 1442 { 1443 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1444 channelLock{*channelMutex}; 1445 1446 /* Always read the channel config */ 1447 if (loadChannelConfig() != 0) 1448 { 1449 log<level::ERR>("Failed to read channel config file"); 1450 throw std::ios_base::failure("Failed to load channel configuration"); 1451 } 1452 1453 /* Populate the channel persist data */ 1454 if (readChannelPersistData() != 0) 1455 { 1456 // Copy default NV data to RW location 1457 std::filesystem::copy_file(channelAccessDefaultFilename, 1458 channelNvDataFilename); 1459 1460 // Load the channel access NV data 1461 if (readChannelPersistData() != 0) 1462 { 1463 log<level::ERR>("Failed to read channel access NV data"); 1464 throw std::ios_base::failure( 1465 "Failed to read channel access NV configuration"); 1466 } 1467 } 1468 1469 // First check the volatile data file 1470 // If not present, load the default values 1471 if (readChannelVolatileData() != 0) 1472 { 1473 // Copy default volatile data to temporary location 1474 // NV file(channelNvDataFilename) must have created by now. 1475 std::filesystem::copy_file(channelNvDataFilename, 1476 channelVolatileDataFilename); 1477 1478 // Load the channel access volatile data 1479 if (readChannelVolatileData() != 0) 1480 { 1481 log<level::ERR>("Failed to read channel access volatile data"); 1482 throw std::ios_base::failure( 1483 "Failed to read channel access volatile configuration"); 1484 } 1485 } 1486 1487 // Synchronize the channel config(priv) with network channel 1488 // configuration(priv) over dbus 1489 if (syncNetworkChannelConfig() != 0) 1490 { 1491 log<level::ERR>( 1492 "Failed to synchronize data with network channel config over dbus"); 1493 throw std::ios_base::failure( 1494 "Failed to synchronize data with network channel config over dbus"); 1495 } 1496 1497 log<level::DEBUG>("Successfully completed channel data initialization."); 1498 return; 1499 } 1500 1501 } // namespace ipmi 1502