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