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(nullptr); 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 int chNum) 141 { 142 if (!isValidChannel(chNum)) 143 { 144 log<level::ERR>("Invalid channel number.", 145 entry("ChannelID:%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 std::size_t pos = path.find(networkIntfObjectBasePath); 172 if (pos == std::string::npos) 173 { 174 log<level::ERR>("Invalid interface path.", 175 entry("PATH:%s", path.c_str())); 176 throw std::invalid_argument("Invalid interface path"); 177 } 178 std::string chName = 179 path.substr(pos + strlen(networkIntfObjectBasePath) + 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 = variant_ns::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 std::string ChannelConfig::getChannelName(const uint8_t chNum) 393 { 394 return channelData[chNum].chName; 395 } 396 397 int ChannelConfig::getChannelActiveSessions(const uint8_t chNum) 398 { 399 // TODO: TEMPORARY FIX 400 // Channels active session count is managed separately 401 // by monitoring channel session which includes LAN and 402 // RAKP layer changes. This will be updated, once the 403 // authentication part is implemented. 404 return channelData[chNum].activeSessCount; 405 } 406 407 size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum) 408 { 409 return channelData[chNum].maxTransferSize; 410 } 411 412 ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t chNum, 413 ChannelInfo& chInfo) 414 { 415 if (!isValidChannel(chNum)) 416 { 417 log<level::DEBUG>("Invalid channel"); 418 return IPMI_CC_INVALID_FIELD_REQUEST; 419 } 420 421 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo), 422 sizeof(channelData[chNum].chInfo), 423 reinterpret_cast<uint8_t*>(&chInfo)); 424 425 return IPMI_CC_OK; 426 } 427 428 ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t chNum, 429 ChannelAccess& chAccessData) 430 { 431 if (!isValidChannel(chNum)) 432 { 433 log<level::DEBUG>("Invalid channel"); 434 return IPMI_CC_INVALID_FIELD_REQUEST; 435 } 436 437 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 438 { 439 log<level::DEBUG>("Session-less channel doesn't have access data."); 440 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 441 } 442 443 if (checkAndReloadVolatileData() != 0) 444 { 445 return IPMI_CC_UNSPECIFIED_ERROR; 446 } 447 448 std::copy_n( 449 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData), 450 sizeof(channelData[chNum].chAccess.chVolatileData), 451 reinterpret_cast<uint8_t*>(&chAccessData)); 452 453 return IPMI_CC_OK; 454 } 455 456 ipmi_ret_t 457 ChannelConfig::setChannelAccessData(const uint8_t chNum, 458 const ChannelAccess& chAccessData, 459 const uint8_t setFlag) 460 { 461 if (!isValidChannel(chNum)) 462 { 463 log<level::DEBUG>("Invalid channel"); 464 return IPMI_CC_INVALID_FIELD_REQUEST; 465 } 466 467 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 468 { 469 log<level::DEBUG>("Session-less channel doesn't have access data."); 470 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 471 } 472 473 if (((setFlag & setAccessMode) && 474 (!isValidAccessMode(chAccessData.accessMode))) || 475 ((setFlag & setPrivLimit) && 476 (!isValidPrivLimit(chAccessData.privLimit)))) 477 { 478 log<level::DEBUG>("Invalid access mode / privilege limit specified"); 479 return IPMI_CC_INVALID_FIELD_REQUEST; 480 } 481 482 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 483 channelLock{*channelMutex}; 484 485 if (checkAndReloadVolatileData() != 0) 486 { 487 return IPMI_CC_UNSPECIFIED_ERROR; 488 } 489 490 if (setFlag & setAccessMode) 491 { 492 channelData[chNum].chAccess.chVolatileData.accessMode = 493 chAccessData.accessMode; 494 } 495 if (setFlag & setUserAuthEnabled) 496 { 497 channelData[chNum].chAccess.chVolatileData.userAuthDisabled = 498 chAccessData.userAuthDisabled; 499 } 500 if (setFlag & setMsgAuthEnabled) 501 { 502 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled = 503 chAccessData.perMsgAuthDisabled; 504 } 505 if (setFlag & setAlertingEnabled) 506 { 507 channelData[chNum].chAccess.chVolatileData.alertingDisabled = 508 chAccessData.alertingDisabled; 509 } 510 if (setFlag & setPrivLimit) 511 { 512 channelData[chNum].chAccess.chVolatileData.privLimit = 513 chAccessData.privLimit; 514 } 515 516 // Write Volatile data to file 517 if (writeChannelVolatileData() != 0) 518 { 519 log<level::DEBUG>("Failed to update the channel volatile data"); 520 return IPMI_CC_UNSPECIFIED_ERROR; 521 } 522 return IPMI_CC_OK; 523 } 524 525 ipmi_ret_t 526 ChannelConfig::getChannelAccessPersistData(const uint8_t chNum, 527 ChannelAccess& chAccessData) 528 { 529 if (!isValidChannel(chNum)) 530 { 531 log<level::DEBUG>("Invalid channel"); 532 return IPMI_CC_INVALID_FIELD_REQUEST; 533 } 534 535 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 536 { 537 log<level::DEBUG>("Session-less channel doesn't have access data."); 538 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 539 } 540 541 if (checkAndReloadNVData() != 0) 542 { 543 return IPMI_CC_UNSPECIFIED_ERROR; 544 } 545 546 std::copy_n(reinterpret_cast<uint8_t*>( 547 &channelData[chNum].chAccess.chNonVolatileData), 548 sizeof(channelData[chNum].chAccess.chNonVolatileData), 549 reinterpret_cast<uint8_t*>(&chAccessData)); 550 551 return IPMI_CC_OK; 552 } 553 554 ipmi_ret_t ChannelConfig::setChannelAccessPersistData( 555 const uint8_t chNum, const ChannelAccess& chAccessData, 556 const uint8_t setFlag) 557 { 558 if (!isValidChannel(chNum)) 559 { 560 log<level::DEBUG>("Invalid channel"); 561 return IPMI_CC_INVALID_FIELD_REQUEST; 562 } 563 564 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 565 { 566 log<level::DEBUG>("Session-less channel doesn't have access data."); 567 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 568 } 569 570 if (((setFlag & setAccessMode) && 571 (!isValidAccessMode(chAccessData.accessMode))) || 572 ((setFlag & setPrivLimit) && 573 (!isValidPrivLimit(chAccessData.privLimit)))) 574 { 575 log<level::DEBUG>("Invalid access mode / privilege limit specified"); 576 return IPMI_CC_INVALID_FIELD_REQUEST; 577 } 578 579 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 580 channelLock{*channelMutex}; 581 582 if (checkAndReloadNVData() != 0) 583 { 584 return IPMI_CC_UNSPECIFIED_ERROR; 585 } 586 587 if (setFlag & setAccessMode) 588 { 589 channelData[chNum].chAccess.chNonVolatileData.accessMode = 590 chAccessData.accessMode; 591 } 592 if (setFlag & setUserAuthEnabled) 593 { 594 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled = 595 chAccessData.userAuthDisabled; 596 } 597 if (setFlag & setMsgAuthEnabled) 598 { 599 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled = 600 chAccessData.perMsgAuthDisabled; 601 } 602 if (setFlag & setAlertingEnabled) 603 { 604 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled = 605 chAccessData.alertingDisabled; 606 } 607 if (setFlag & setPrivLimit) 608 { 609 // Send Update to network channel config interfaces over dbus 610 std::string privStr = convertToPrivLimitString(chAccessData.privLimit); 611 std::string networkIntfObj = std::string(networkIntfObjectBasePath) + 612 "/" + channelData[chNum].chName; 613 try 614 { 615 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj, 616 networkChConfigIntfName, 617 privilegePropertyString, privStr)) 618 { 619 log<level::DEBUG>( 620 "Network interface does not exist", 621 entry("INTERFACE:%s", channelData[chNum].chName.c_str())); 622 return IPMI_CC_UNSPECIFIED_ERROR; 623 } 624 } 625 catch (const sdbusplus::exception::SdBusError& e) 626 { 627 log<level::ERR>("Exception: Network interface does not exist"); 628 return IPMI_CC_INVALID_FIELD_REQUEST; 629 } 630 signalFlag |= (1 << chNum); 631 channelData[chNum].chAccess.chNonVolatileData.privLimit = 632 chAccessData.privLimit; 633 } 634 635 // Write persistent data to file 636 if (writeChannelPersistData() != 0) 637 { 638 log<level::DEBUG>("Failed to update the presist data file"); 639 return IPMI_CC_UNSPECIFIED_ERROR; 640 } 641 return IPMI_CC_OK; 642 } 643 644 ipmi_ret_t 645 ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum, 646 uint8_t& authTypeSupported) 647 { 648 if (!isValidChannel(chNum)) 649 { 650 log<level::DEBUG>("Invalid channel"); 651 return IPMI_CC_INVALID_FIELD_REQUEST; 652 } 653 654 authTypeSupported = channelData[chNum].chInfo.authTypeSupported; 655 return IPMI_CC_OK; 656 } 657 658 ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum, 659 const uint8_t priv, 660 EAuthType& authType) 661 { 662 if (!isValidChannel(chNum)) 663 { 664 log<level::DEBUG>("Invalid channel"); 665 return IPMI_CC_INVALID_FIELD_REQUEST; 666 } 667 668 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 669 { 670 log<level::DEBUG>("Sessionless channel doesn't have access data."); 671 return IPMI_CC_INVALID_FIELD_REQUEST; 672 } 673 674 if (!isValidPrivLimit(priv)) 675 { 676 log<level::DEBUG>("Invalid privilege specified."); 677 return IPMI_CC_INVALID_FIELD_REQUEST; 678 } 679 680 // TODO: Hardcoded for now. Need to implement. 681 authType = EAuthType::none; 682 683 return IPMI_CC_OK; 684 } 685 686 std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName) 687 { 688 struct stat fileStat; 689 if (stat(fileName.c_str(), &fileStat) != 0) 690 { 691 log<level::DEBUG>("Error in getting last updated time stamp"); 692 return -EIO; 693 } 694 return fileStat.st_mtime; 695 } 696 697 EChannelAccessMode 698 ChannelConfig::convertToAccessModeIndex(const std::string& mode) 699 { 700 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode); 701 if (iter == accessModeList.end()) 702 { 703 log<level::ERR>("Invalid access mode.", 704 entry("MODE_STR=%s", mode.c_str())); 705 throw std::invalid_argument("Invalid access mode."); 706 } 707 708 return static_cast<EChannelAccessMode>( 709 std::distance(accessModeList.begin(), iter)); 710 } 711 712 std::string ChannelConfig::convertToAccessModeString(const uint8_t value) 713 { 714 if (accessModeList.size() <= value) 715 { 716 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value)); 717 throw std::invalid_argument("Invalid access mode."); 718 } 719 720 return accessModeList.at(value); 721 } 722 723 CommandPrivilege 724 ChannelConfig::convertToPrivLimitIndex(const std::string& value) 725 { 726 auto iter = std::find(privList.begin(), privList.end(), value); 727 if (iter == privList.end()) 728 { 729 log<level::ERR>("Invalid privilege.", 730 entry("PRIV_STR=%s", value.c_str())); 731 throw std::invalid_argument("Invalid privilege."); 732 } 733 734 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter)); 735 } 736 737 std::string ChannelConfig::convertToPrivLimitString(const uint8_t value) 738 { 739 if (privList.size() <= value) 740 { 741 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value)); 742 throw std::invalid_argument("Invalid privilege."); 743 } 744 745 return privList.at(value); 746 } 747 748 EChannelSessSupported 749 ChannelConfig::convertToSessionSupportIndex(const std::string& value) 750 { 751 auto iter = 752 std::find(sessionSupportList.begin(), sessionSupportList.end(), value); 753 if (iter == sessionSupportList.end()) 754 { 755 log<level::ERR>("Invalid session supported.", 756 entry("SESS_STR=%s", value.c_str())); 757 throw std::invalid_argument("Invalid session supported."); 758 } 759 760 return static_cast<EChannelSessSupported>( 761 std::distance(sessionSupportList.begin(), iter)); 762 } 763 764 EChannelMediumType 765 ChannelConfig::convertToMediumTypeIndex(const std::string& value) 766 { 767 std::unordered_map<std::string, EChannelMediumType>::iterator it = 768 mediumTypeMap.find(value); 769 if (it == mediumTypeMap.end()) 770 { 771 log<level::ERR>("Invalid medium type.", 772 entry("MEDIUM_STR=%s", value.c_str())); 773 throw std::invalid_argument("Invalid medium type."); 774 } 775 776 return static_cast<EChannelMediumType>(it->second); 777 } 778 779 EChannelProtocolType 780 ChannelConfig::convertToProtocolTypeIndex(const std::string& value) 781 { 782 std::unordered_map<std::string, EChannelProtocolType>::iterator it = 783 protocolTypeMap.find(value); 784 if (it == protocolTypeMap.end()) 785 { 786 log<level::ERR>("Invalid protocol type.", 787 entry("PROTO_STR=%s", value.c_str())); 788 throw std::invalid_argument("Invalid protocol type."); 789 } 790 791 return static_cast<EChannelProtocolType>(it->second); 792 } 793 794 uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum) 795 { 796 797 // TODO: There is limitation in current design. we cannot detect exact 798 // LAN interface(eth0 or eth1) so Implementation may be updated 799 // when there is any design update to figure out all the interfaces 800 // independently based on the message. 801 802 static uint8_t curChannel = 0xFF; 803 804 if (curChannel == 0xFF) 805 { 806 auto it = interfaceMap.find(getInterfaceIndex()); 807 if (it == interfaceMap.end()) 808 { 809 log<level::ERR>("Invalid Interface type ", 810 entry("InterfaceIndex: %d", getInterfaceIndex())); 811 throw std::invalid_argument("Invalid interface type."); 812 } 813 814 for (auto& channel : channelData) 815 { 816 std::string& interfaceName = it->second; 817 if (channel.chName == interfaceName) 818 { 819 curChannel = channel.chID; 820 break; 821 } 822 } 823 } 824 return ((chNum == currentChNum) ? curChannel : chNum); 825 } 826 827 Json ChannelConfig::readJsonFile(const std::string& configFile) 828 { 829 std::ifstream jsonFile(configFile); 830 if (!jsonFile.good()) 831 { 832 log<level::ERR>("JSON file not found"); 833 return nullptr; 834 } 835 836 Json data = nullptr; 837 try 838 { 839 data = Json::parse(jsonFile, nullptr, false); 840 } 841 catch (Json::parse_error& e) 842 { 843 log<level::DEBUG>("Corrupted channel config.", 844 entry("MSG: %s", e.what())); 845 throw std::runtime_error("Corrupted channel config file"); 846 } 847 848 return data; 849 } 850 851 int ChannelConfig::writeJsonFile(const std::string& configFile, 852 const Json& jsonData) 853 { 854 std::ofstream jsonFile(configFile); 855 if (!jsonFile.good()) 856 { 857 log<level::ERR>("JSON file not found"); 858 return -EIO; 859 } 860 861 // Write JSON to file 862 jsonFile << jsonData; 863 864 jsonFile.flush(); 865 return 0; 866 } 867 868 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum, 869 const std::string& chName) 870 { 871 channelData[chNum].chName = chName; 872 channelData[chNum].chID = chNum; 873 channelData[chNum].isChValid = false; 874 channelData[chNum].activeSessCount = 0; 875 876 channelData[chNum].chInfo.mediumType = defaultMediumType; 877 channelData[chNum].chInfo.protocolType = defaultProtocolType; 878 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported; 879 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState; 880 channelData[chNum].chInfo.authTypeSupported = defaultAuthType; 881 } 882 883 int ChannelConfig::loadChannelConfig() 884 { 885 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 886 channelLock{*channelMutex}; 887 888 Json data = readJsonFile(channelConfigDefaultFilename); 889 if (data.empty()) 890 { 891 log<level::DEBUG>("Error in opening IPMI Channel data file"); 892 return -EIO; 893 } 894 895 channelData.fill(ChannelProperties{}); 896 897 for (int chNum = 0; chNum < maxIpmiChannels; chNum++) 898 { 899 try 900 { 901 std::string chKey = std::to_string(chNum); 902 Json jsonChData = data[chKey].get<Json>(); 903 if (jsonChData.is_null()) 904 { 905 log<level::WARNING>( 906 "Channel not configured so loading default.", 907 entry("CHANNEL_NUM:%d", chNum)); 908 // If user didn't want to configure specific channel (say 909 // reserved channel), then load that index with default values. 910 setDefaultChannelConfig(chNum, defaultChannelName); 911 continue; 912 } 913 Json jsonChInfo = jsonChData[channelInfoString].get<Json>(); 914 if (jsonChInfo.is_null()) 915 { 916 log<level::ERR>("Invalid/corrupted channel config file"); 917 return -EBADMSG; 918 } 919 920 ChannelProperties& chData = channelData[chNum]; 921 chData.chName = jsonChData[nameString].get<std::string>(); 922 chData.chID = chNum; 923 chData.isChValid = jsonChData[isValidString].get<bool>(); 924 chData.activeSessCount = jsonChData.value(activeSessionsString, 0); 925 chData.maxTransferSize = 926 jsonChData.value(maxTransferSizeString, smallChannelSize); 927 std::string medTypeStr = 928 jsonChInfo[mediumTypeString].get<std::string>(); 929 chData.chInfo.mediumType = 930 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr)); 931 std::string protoTypeStr = 932 jsonChInfo[protocolTypeString].get<std::string>(); 933 chData.chInfo.protocolType = 934 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr)); 935 std::string sessStr = 936 jsonChInfo[sessionSupportedString].get<std::string>(); 937 chData.chInfo.sessionSupported = 938 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr)); 939 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>(); 940 chData.chInfo.authTypeSupported = defaultAuthType; 941 } 942 catch (const Json::exception& e) 943 { 944 log<level::DEBUG>("Json Exception caught.", 945 entry("MSG:%s", e.what())); 946 return -EBADMSG; 947 } 948 catch (const std::invalid_argument& e) 949 { 950 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what())); 951 return -EBADMSG; 952 } 953 } 954 955 return 0; 956 } 957 958 int ChannelConfig::readChannelVolatileData() 959 { 960 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 961 channelLock{*channelMutex}; 962 963 Json data = readJsonFile(channelVolatileDataFilename); 964 if (data == nullptr) 965 { 966 log<level::DEBUG>("Error in opening IPMI Channel data file"); 967 return -EIO; 968 } 969 try 970 { 971 // Fill in global structure 972 for (auto it = data.begin(); it != data.end(); ++it) 973 { 974 std::string chKey = it.key(); 975 uint8_t chNum = std::stoi(chKey, nullptr, 10); 976 if ((chNum < 0) || (chNum > maxIpmiChannels)) 977 { 978 log<level::DEBUG>( 979 "Invalid channel access entry in config file"); 980 throw std::out_of_range("Out of range - channel number"); 981 } 982 Json jsonChData = it.value(); 983 if (!jsonChData.is_null()) 984 { 985 std::string accModeStr = 986 jsonChData[accessModeString].get<std::string>(); 987 channelData[chNum].chAccess.chVolatileData.accessMode = 988 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr)); 989 channelData[chNum].chAccess.chVolatileData.userAuthDisabled = 990 jsonChData[userAuthDisabledString].get<bool>(); 991 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled = 992 jsonChData[perMsgAuthDisabledString].get<bool>(); 993 channelData[chNum].chAccess.chVolatileData.alertingDisabled = 994 jsonChData[alertingDisabledString].get<bool>(); 995 std::string privStr = 996 jsonChData[privLimitString].get<std::string>(); 997 channelData[chNum].chAccess.chVolatileData.privLimit = 998 static_cast<uint8_t>(convertToPrivLimitIndex(privStr)); 999 } 1000 else 1001 { 1002 log<level::ERR>( 1003 "Invalid/corrupted volatile channel access file", 1004 entry("FILE: %s", channelVolatileDataFilename)); 1005 throw std::runtime_error( 1006 "Corrupted volatile channel access file"); 1007 } 1008 } 1009 } 1010 catch (const Json::exception& e) 1011 { 1012 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what())); 1013 throw std::runtime_error("Corrupted volatile channel access file"); 1014 } 1015 catch (const std::invalid_argument& e) 1016 { 1017 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what())); 1018 throw std::runtime_error("Corrupted volatile channel access file"); 1019 } 1020 1021 // Update the timestamp 1022 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename); 1023 return 0; 1024 } 1025 1026 int ChannelConfig::readChannelPersistData() 1027 { 1028 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1029 channelLock{*channelMutex}; 1030 1031 Json data = readJsonFile(channelNvDataFilename); 1032 if (data == nullptr) 1033 { 1034 log<level::DEBUG>("Error in opening IPMI Channel data file"); 1035 return -EIO; 1036 } 1037 try 1038 { 1039 // Fill in global structure 1040 for (auto it = data.begin(); it != data.end(); ++it) 1041 { 1042 std::string chKey = it.key(); 1043 uint8_t chNum = std::stoi(chKey, nullptr, 10); 1044 if ((chNum < 0) || (chNum > maxIpmiChannels)) 1045 { 1046 log<level::DEBUG>( 1047 "Invalid channel access entry in config file"); 1048 throw std::out_of_range("Out of range - channel number"); 1049 } 1050 Json jsonChData = it.value(); 1051 if (!jsonChData.is_null()) 1052 { 1053 std::string accModeStr = 1054 jsonChData[accessModeString].get<std::string>(); 1055 channelData[chNum].chAccess.chNonVolatileData.accessMode = 1056 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr)); 1057 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled = 1058 jsonChData[userAuthDisabledString].get<bool>(); 1059 channelData[chNum] 1060 .chAccess.chNonVolatileData.perMsgAuthDisabled = 1061 jsonChData[perMsgAuthDisabledString].get<bool>(); 1062 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled = 1063 jsonChData[alertingDisabledString].get<bool>(); 1064 std::string privStr = 1065 jsonChData[privLimitString].get<std::string>(); 1066 channelData[chNum].chAccess.chNonVolatileData.privLimit = 1067 static_cast<uint8_t>(convertToPrivLimitIndex(privStr)); 1068 } 1069 else 1070 { 1071 log<level::ERR>("Invalid/corrupted nv channel access file", 1072 entry("FILE:%s", channelNvDataFilename)); 1073 throw std::runtime_error("Corrupted nv channel access file"); 1074 } 1075 } 1076 } 1077 catch (const Json::exception& e) 1078 { 1079 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what())); 1080 throw std::runtime_error("Corrupted nv channel access file"); 1081 } 1082 catch (const std::invalid_argument& e) 1083 { 1084 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what())); 1085 throw std::runtime_error("Corrupted nv channel access file"); 1086 } 1087 1088 // Update the timestamp 1089 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename); 1090 return 0; 1091 } 1092 1093 int ChannelConfig::writeChannelVolatileData() 1094 { 1095 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1096 channelLock{*channelMutex}; 1097 Json outData; 1098 1099 try 1100 { 1101 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1102 { 1103 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1104 { 1105 Json jsonObj; 1106 std::string chKey = std::to_string(chNum); 1107 std::string accModeStr = convertToAccessModeString( 1108 channelData[chNum].chAccess.chVolatileData.accessMode); 1109 jsonObj[accessModeString] = accModeStr; 1110 jsonObj[userAuthDisabledString] = 1111 channelData[chNum].chAccess.chVolatileData.userAuthDisabled; 1112 jsonObj[perMsgAuthDisabledString] = 1113 channelData[chNum] 1114 .chAccess.chVolatileData.perMsgAuthDisabled; 1115 jsonObj[alertingDisabledString] = 1116 channelData[chNum].chAccess.chVolatileData.alertingDisabled; 1117 std::string privStr = convertToPrivLimitString( 1118 channelData[chNum].chAccess.chVolatileData.privLimit); 1119 jsonObj[privLimitString] = privStr; 1120 1121 outData[chKey] = jsonObj; 1122 } 1123 } 1124 } 1125 catch (const std::invalid_argument& e) 1126 { 1127 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what())); 1128 return -EINVAL; 1129 } 1130 1131 if (writeJsonFile(channelVolatileDataFilename, outData) != 0) 1132 { 1133 log<level::DEBUG>("Error in write JSON data to file"); 1134 return -EIO; 1135 } 1136 1137 // Update the timestamp 1138 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename); 1139 return 0; 1140 } 1141 1142 int ChannelConfig::writeChannelPersistData() 1143 { 1144 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1145 channelLock{*channelMutex}; 1146 Json outData; 1147 1148 try 1149 { 1150 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1151 { 1152 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1153 { 1154 Json jsonObj; 1155 std::string chKey = std::to_string(chNum); 1156 std::string accModeStr = convertToAccessModeString( 1157 channelData[chNum].chAccess.chNonVolatileData.accessMode); 1158 jsonObj[accessModeString] = accModeStr; 1159 jsonObj[userAuthDisabledString] = 1160 channelData[chNum] 1161 .chAccess.chNonVolatileData.userAuthDisabled; 1162 jsonObj[perMsgAuthDisabledString] = 1163 channelData[chNum] 1164 .chAccess.chNonVolatileData.perMsgAuthDisabled; 1165 jsonObj[alertingDisabledString] = 1166 channelData[chNum] 1167 .chAccess.chNonVolatileData.alertingDisabled; 1168 std::string privStr = convertToPrivLimitString( 1169 channelData[chNum].chAccess.chNonVolatileData.privLimit); 1170 jsonObj[privLimitString] = privStr; 1171 1172 outData[chKey] = jsonObj; 1173 } 1174 } 1175 } 1176 catch (const std::invalid_argument& e) 1177 { 1178 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what())); 1179 return -EINVAL; 1180 } 1181 1182 if (writeJsonFile(channelNvDataFilename, outData) != 0) 1183 { 1184 log<level::DEBUG>("Error in write JSON data to file"); 1185 return -EIO; 1186 } 1187 1188 // Update the timestamp 1189 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename); 1190 return 0; 1191 } 1192 1193 int ChannelConfig::checkAndReloadNVData() 1194 { 1195 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename); 1196 int ret = 0; 1197 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO) 1198 { 1199 try 1200 { 1201 ret = readChannelPersistData(); 1202 } 1203 catch (const std::exception& e) 1204 { 1205 log<level::ERR>("Exception caught in readChannelPersistData.", 1206 entry("MSG=%s", e.what())); 1207 ret = -EIO; 1208 } 1209 } 1210 return ret; 1211 } 1212 1213 int ChannelConfig::checkAndReloadVolatileData() 1214 { 1215 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename); 1216 int ret = 0; 1217 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO) 1218 { 1219 try 1220 { 1221 ret = readChannelVolatileData(); 1222 } 1223 catch (const std::exception& e) 1224 { 1225 log<level::ERR>("Exception caught in readChannelVolatileData.", 1226 entry("MSG=%s", e.what())); 1227 ret = -EIO; 1228 } 1229 } 1230 return ret; 1231 } 1232 1233 int ChannelConfig::setDbusProperty(const std::string& service, 1234 const std::string& objPath, 1235 const std::string& interface, 1236 const std::string& property, 1237 const DbusVariant& value) 1238 { 1239 try 1240 { 1241 auto method = 1242 bus.new_method_call(service.c_str(), objPath.c_str(), 1243 "org.freedesktop.DBus.Properties", "Set"); 1244 1245 method.append(interface, property, value); 1246 1247 auto reply = bus.call(method); 1248 } 1249 catch (const sdbusplus::exception::SdBusError& e) 1250 { 1251 log<level::DEBUG>("set-property failed", 1252 entry("SERVICE:%s", service.c_str()), 1253 entry("OBJPATH:%s", objPath.c_str()), 1254 entry("INTERFACE:%s", interface.c_str()), 1255 entry("PROP:%s", property.c_str())); 1256 return -EIO; 1257 } 1258 1259 return 0; 1260 } 1261 1262 int ChannelConfig::getDbusProperty(const std::string& service, 1263 const std::string& objPath, 1264 const std::string& interface, 1265 const std::string& property, 1266 DbusVariant& value) 1267 { 1268 try 1269 { 1270 auto method = 1271 bus.new_method_call(service.c_str(), objPath.c_str(), 1272 "org.freedesktop.DBus.Properties", "Get"); 1273 1274 method.append(interface, property); 1275 1276 auto reply = bus.call(method); 1277 reply.read(value); 1278 } 1279 catch (const sdbusplus::exception::SdBusError& e) 1280 { 1281 log<level::DEBUG>("get-property failed", 1282 entry("SERVICE:%s", service.c_str()), 1283 entry("OBJPATH:%s", objPath.c_str()), 1284 entry("INTERFACE:%s", interface.c_str()), 1285 entry("PROP:%s", property.c_str())); 1286 return -EIO; 1287 } 1288 return 0; 1289 } 1290 1291 int ChannelConfig::syncNetworkChannelConfig() 1292 { 1293 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1294 channelLock{*channelMutex}; 1295 bool isUpdated = false; 1296 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++) 1297 { 1298 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none) 1299 { 1300 std::string intfPrivStr; 1301 try 1302 { 1303 std::string networkIntfObj = 1304 std::string(networkIntfObjectBasePath) + "/" + 1305 channelData[chNum].chName; 1306 DbusVariant variant; 1307 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj, 1308 networkChConfigIntfName, 1309 privilegePropertyString, variant)) 1310 { 1311 log<level::DEBUG>("Network interface does not exist", 1312 entry("INTERFACE:%s", 1313 channelData[chNum].chName.c_str())); 1314 continue; 1315 } 1316 intfPrivStr = variant_ns::get<std::string>(variant); 1317 } 1318 catch (const variant_ns::bad_variant_access& e) 1319 { 1320 log<level::DEBUG>( 1321 "exception: Network interface does not exist"); 1322 continue; 1323 } 1324 catch (const sdbusplus::exception::SdBusError& e) 1325 { 1326 log<level::DEBUG>( 1327 "exception: Network interface does not exist"); 1328 continue; 1329 } 1330 1331 uint8_t intfPriv = 1332 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr)); 1333 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != 1334 intfPriv) 1335 { 1336 isUpdated = true; 1337 channelData[chNum].chAccess.chNonVolatileData.privLimit = 1338 intfPriv; 1339 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv; 1340 } 1341 } 1342 } 1343 1344 if (isUpdated) 1345 { 1346 // Write persistent data to file 1347 if (writeChannelPersistData() != 0) 1348 { 1349 log<level::DEBUG>("Failed to update the persistent data file"); 1350 return -EIO; 1351 } 1352 // Write Volatile data to file 1353 if (writeChannelVolatileData() != 0) 1354 { 1355 log<level::DEBUG>("Failed to update the channel volatile data"); 1356 return -EIO; 1357 } 1358 } 1359 1360 return 0; 1361 } 1362 1363 void ChannelConfig::initChannelPersistData() 1364 { 1365 /* Always read the channel config */ 1366 if (loadChannelConfig() != 0) 1367 { 1368 log<level::ERR>("Failed to read channel config file"); 1369 throw std::ios_base::failure("Failed to load channel configuration"); 1370 } 1371 1372 /* Populate the channel persist data */ 1373 if (readChannelPersistData() != 0) 1374 { 1375 // Copy default NV data to RW location 1376 std::experimental::filesystem::copy_file(channelAccessDefaultFilename, 1377 channelNvDataFilename); 1378 1379 // Load the channel access NV data 1380 if (readChannelPersistData() != 0) 1381 { 1382 log<level::ERR>("Failed to read channel access NV data"); 1383 throw std::ios_base::failure( 1384 "Failed to read channel access NV configuration"); 1385 } 1386 } 1387 1388 // First check the volatile data file 1389 // If not present, load the default values 1390 if (readChannelVolatileData() != 0) 1391 { 1392 // Copy default volatile data to temporary location 1393 // NV file(channelNvDataFilename) must have created by now. 1394 std::experimental::filesystem::copy_file(channelNvDataFilename, 1395 channelVolatileDataFilename); 1396 1397 // Load the channel access volatile data 1398 if (readChannelVolatileData() != 0) 1399 { 1400 log<level::ERR>("Failed to read channel access volatile data"); 1401 throw std::ios_base::failure( 1402 "Failed to read channel access volatile configuration"); 1403 } 1404 } 1405 1406 // Synchronize the channel config(priv) with network channel 1407 // configuration(priv) over dbus 1408 if (syncNetworkChannelConfig() != 0) 1409 { 1410 log<level::ERR>( 1411 "Failed to synchronize data with network channel config over dbus"); 1412 throw std::ios_base::failure( 1413 "Failed to synchronize data with network channel config over dbus"); 1414 } 1415 1416 log<level::DEBUG>("Successfully completed channel data initialization."); 1417 return; 1418 } 1419 1420 } // namespace ipmi 1421