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