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