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