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