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