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