summaryrefslogtreecommitdiffstats
path: root/user_channel/channel_mgmt.cpp
diff options
context:
space:
mode:
authorAppaRao Puli <apparao.puli@intel.com>2018-05-24 16:45:30 +0530
committerRichard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>2018-11-20 10:09:26 +0530
commit071f3f2f298ab4a4799b7fcdba3255dfd999452d (patch)
treee56a267bf7e4eca8efc008d3a3d8b4b405268fcd /user_channel/channel_mgmt.cpp
parentb849110d32da5ca61f165abf553eac5b383d4f69 (diff)
downloadphosphor-host-ipmid-071f3f2f298ab4a4799b7fcdba3255dfd999452d.tar.gz
phosphor-host-ipmid-071f3f2f298ab4a4799b7fcdba3255dfd999452d.zip
IPMI Channel commands implementation
IPMI Channel commands implemenation - squashed commit e9a75d8dd6e89d17381f0310c7930586c6b79996 Author: AppaRao Puli <apparao.puli@intel.com> Date: Thu Jul 5 14:47:22 2018 +0530 Channel layer separation De-coupling the channel management from ipmi channel commands implementation. This gives flexibility to load only needed stuff in different modules(host-ipmi or netipmid) Change-Id: Ib334562beb9325f7768ed6a15475cae15af17b19 Signed-off-by: AppaRao Puli <apparao.puli@intel.com> Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> commit 726ddf2af678ea6773f4b4b918fbd49be8c83e6a Author: AppaRao Puli <apparao.puli@intel.com> Date: Thu May 24 16:45:30 2018 +0530 IPMI Channel commands implementation Following IPMI channel commands are implemented. 1) Set channel access (0x40) 2) Get channel access (0x41) 3) Get channel info (0x42) Also added code supported for LAN configuration parameters 1) Authentication Type Support (selector #1) 2) Authentication Type Enables (selector #2) Change-Id: Ic4156378c7756eca383dc3da52114fd119346ca6 Signed-off-by: AppaRao Puli <apparao.puli@intel.com> Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> Change-Id: Ic4156378c7756eca383dc3da52114fd119346ca6 Signed-off-by: AppaRao Puli <apparao.puli@intel.com> Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
Diffstat (limited to 'user_channel/channel_mgmt.cpp')
-rw-r--r--user_channel/channel_mgmt.cpp1027
1 files changed, 1027 insertions, 0 deletions
diff --git a/user_channel/channel_mgmt.cpp b/user_channel/channel_mgmt.cpp
new file mode 100644
index 0000000..0db54b6
--- /dev/null
+++ b/user_channel/channel_mgmt.cpp
@@ -0,0 +1,1027 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "channel_mgmt.hpp"
+
+#include "apphandler.hpp"
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <cerrno>
+#include <experimental/filesystem>
+#include <fstream>
+#include <phosphor-logging/log.hpp>
+#include <unordered_map>
+
+namespace ipmi
+{
+
+using namespace phosphor::logging;
+
+static constexpr const char* channelAccessDefaultFilename =
+ "/usr/share/ipmi-providers/channel_access.json";
+static constexpr const char* channelConfigDefaultFilename =
+ "/usr/share/ipmi-providers/channel_config.json";
+static constexpr const char* channelNvDataFilename =
+ "/var/lib/ipmi/channel_access_nv.json";
+static constexpr const char* channelVolatileDataFilename =
+ "/run/ipmi/channel_access_volatile.json";
+
+// STRING DEFINES: Should sync with key's in JSON
+static constexpr const char* nameString = "name";
+static constexpr const char* isValidString = "is_valid";
+static constexpr const char* activeSessionsString = "active_sessions";
+static constexpr const char* channelInfoString = "channel_info";
+static constexpr const char* mediumTypeString = "medium_type";
+static constexpr const char* protocolTypeString = "protocol_type";
+static constexpr const char* sessionSupportedString = "session_supported";
+static constexpr const char* isIpmiString = "is_ipmi";
+static constexpr const char* authTypeSupportedString = "auth_type_supported";
+static constexpr const char* accessModeString = "access_mode";
+static constexpr const char* userAuthDisabledString = "user_auth_disabled";
+static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
+static constexpr const char* alertingDisabledString = "alerting_disabled";
+static constexpr const char* privLimitString = "priv_limit";
+static constexpr const char* authTypeEnabledString = "auth_type_enabled";
+
+// Default values
+static constexpr const char* defaultChannelName = "RESERVED";
+static constexpr const uint8_t defaultMediumType =
+ static_cast<uint8_t>(EChannelMediumType::reserved);
+static constexpr const uint8_t defaultProtocolType =
+ static_cast<uint8_t>(EChannelProtocolType::reserved);
+static constexpr const uint8_t defaultSessionSupported =
+ static_cast<uint8_t>(EChannelSessSupported::none);
+static constexpr const uint8_t defaultAuthType =
+ static_cast<uint8_t>(EAuthType::none);
+static constexpr const bool defaultIsIpmiState = false;
+
+// String mappings use in JSON config file
+static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
+ {"reserved", EChannelMediumType::reserved},
+ {"ipmb", EChannelMediumType::ipmb},
+ {"icmb-v1.0", EChannelMediumType::icmbV10},
+ {"icmb-v0.9", EChannelMediumType::icmbV09},
+ {"lan-802.3", EChannelMediumType::lan8032},
+ {"serial", EChannelMediumType::serial},
+ {"other-lan", EChannelMediumType::otherLan},
+ {"pci-smbus", EChannelMediumType::pciSmbus},
+ {"smbus-v1.0", EChannelMediumType::smbusV11},
+ {"smbus-v2.0", EChannelMediumType::smbusV20},
+ {"usb-1x", EChannelMediumType::usbV1x},
+ {"usb-2x", EChannelMediumType::usbV2x},
+ {"system-interface", EChannelMediumType::systemInterface},
+ {"oem", EChannelMediumType::oem},
+ {"unknown", EChannelMediumType::unknown}};
+
+static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
+ {"na", EChannelProtocolType::na},
+ {"ipmb-1.0", EChannelProtocolType::ipmbV10},
+ {"icmb-2.0", EChannelProtocolType::icmbV11},
+ {"reserved", EChannelProtocolType::reserved},
+ {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
+ {"kcs", EChannelProtocolType::kcs},
+ {"smic", EChannelProtocolType::smic},
+ {"bt-10", EChannelProtocolType::bt10},
+ {"bt-15", EChannelProtocolType::bt15},
+ {"tmode", EChannelProtocolType::tMode},
+ {"oem", EChannelProtocolType::oem}};
+
+static std::array<std::string, 4> accessModeList = {
+ "disabled", "pre-boot", "always_available", "shared"};
+
+static std::array<std::string, 4> sessionSupportList = {
+ "session-less", "single-session", "multi-session", "session-based"};
+
+static std::array<std::string, PRIVILEGE_OEM + 1> privList = {
+ "priv-reserved", "priv-callback", "priv-user",
+ "priv-operator", "priv-admin", "priv-oem"};
+
+ChannelConfig& getChannelConfigObject()
+{
+ static ChannelConfig channelConfig;
+ return channelConfig;
+}
+
+ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
+{
+ std::ofstream mutexCleanUpFile;
+ mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
+ std::ofstream::out | std::ofstream::app);
+ if (!mutexCleanUpFile.good())
+ {
+ log<level::DEBUG>("Unable to open mutex cleanup file");
+ return;
+ }
+ mutexCleanUpFile.close();
+ mutexCleanupLock =
+ boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
+ if (mutexCleanupLock.try_lock())
+ {
+ boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
+ channelMutex =
+ std::make_unique<boost::interprocess::named_recursive_mutex>(
+ boost::interprocess::open_or_create, ipmiChannelMutex);
+ mutexCleanupLock.lock_sharable();
+ }
+ else
+ {
+ mutexCleanupLock.lock_sharable();
+ channelMutex =
+ std::make_unique<boost::interprocess::named_recursive_mutex>(
+ boost::interprocess::open_or_create, ipmiChannelMutex);
+ }
+
+ initChannelPersistData();
+}
+
+bool ChannelConfig::isValidChannel(const uint8_t& chNum)
+{
+ if (chNum > maxIpmiChannels)
+ {
+ log<level::DEBUG>("Invalid channel ID - Out of range");
+ return false;
+ }
+
+ if (channelData[chNum].isChValid == false)
+ {
+ log<level::DEBUG>("Channel is not valid");
+ return false;
+ }
+
+ return true;
+}
+
+EChannelSessSupported
+ ChannelConfig::getChannelSessionSupport(const uint8_t& chNum)
+{
+ EChannelSessSupported chSessSupport =
+ (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
+ return chSessSupport;
+}
+
+bool ChannelConfig::isValidAuthType(const uint8_t& chNum,
+ const EAuthType& authType)
+{
+ if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
+ {
+ log<level::DEBUG>("Invalid authentication type");
+ return false;
+ }
+
+ uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
+ if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
+ {
+ log<level::DEBUG>("Authentication type is not supported.");
+ return false;
+ }
+
+ return true;
+}
+
+int ChannelConfig::getChannelActiveSessions(const uint8_t& chNum)
+{
+ // TODO: TEMPORARY FIX
+ // Channels active session count is managed separatly
+ // by monitoring channel session which includes LAN and
+ // RAKP layer changes. This will be updated, once the
+ // authentication part is implemented.
+ return channelData[chNum].activeSessCount;
+}
+
+ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t& chNum,
+ ChannelInfo& chInfo)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
+ sizeof(channelData[chNum].chInfo),
+ reinterpret_cast<uint8_t*>(&chInfo));
+
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t& chNum,
+ ChannelAccess& chAccessData)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
+ {
+ log<level::DEBUG>("Session-less channel doesn't have access data.");
+ return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ }
+
+ if (checkAndReloadVolatileData() != 0)
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ std::copy_n(
+ reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
+ sizeof(channelData[chNum].chAccess.chVolatileData),
+ reinterpret_cast<uint8_t*>(&chAccessData));
+
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t
+ ChannelConfig::setChannelAccessData(const uint8_t& chNum,
+ const ChannelAccess& chAccessData,
+ const uint8_t& setFlag)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
+ {
+ log<level::DEBUG>("Session-less channel doesn't have access data.");
+ return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ }
+
+ if ((setFlag & setAccessMode) &&
+ (!isValidAccessMode(chAccessData.accessMode)))
+ {
+ log<level::DEBUG>("Invalid access mode specified");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
+ if (checkAndReloadVolatileData() != 0)
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ if (setFlag & setAccessMode)
+ {
+ channelData[chNum].chAccess.chVolatileData.accessMode =
+ chAccessData.accessMode;
+ }
+ if (setFlag & setUserAuthEnabled)
+ {
+ channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
+ chAccessData.userAuthDisabled;
+ }
+ if (setFlag & setMsgAuthEnabled)
+ {
+ channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
+ chAccessData.perMsgAuthDisabled;
+ }
+ if (setFlag & setAlertingEnabled)
+ {
+ channelData[chNum].chAccess.chVolatileData.alertingDisabled =
+ chAccessData.alertingDisabled;
+ }
+ if (setFlag & setPrivLimit)
+ {
+ channelData[chNum].chAccess.chVolatileData.privLimit =
+ chAccessData.privLimit;
+ }
+
+ // Write Volatile data to file
+ if (writeChannelVolatileData() != 0)
+ {
+ log<level::DEBUG>("Failed to update the channel volatile data");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t
+ ChannelConfig::getChannelAccessPersistData(const uint8_t& chNum,
+ ChannelAccess& chAccessData)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
+ {
+ log<level::DEBUG>("Session-less channel doesn't have access data.");
+ return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ }
+
+ if (checkAndReloadNVData() != 0)
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ std::copy_n(reinterpret_cast<uint8_t*>(
+ &channelData[chNum].chAccess.chNonVolatileData),
+ sizeof(channelData[chNum].chAccess.chNonVolatileData),
+ reinterpret_cast<uint8_t*>(&chAccessData));
+
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
+ const uint8_t& chNum, const ChannelAccess& chAccessData,
+ const uint8_t& setFlag)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
+ {
+ log<level::DEBUG>("Session-less channel doesn't have access data.");
+ return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ }
+
+ if ((setFlag & setAccessMode) &&
+ (!isValidAccessMode(chAccessData.accessMode)))
+ {
+ log<level::DEBUG>("Invalid access mode specified");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
+ if (checkAndReloadNVData() != 0)
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ if (setFlag & setAccessMode)
+ {
+ channelData[chNum].chAccess.chNonVolatileData.accessMode =
+ chAccessData.accessMode;
+ }
+ if (setFlag & setUserAuthEnabled)
+ {
+ channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
+ chAccessData.userAuthDisabled;
+ }
+ if (setFlag & setMsgAuthEnabled)
+ {
+ channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
+ chAccessData.perMsgAuthDisabled;
+ }
+ if (setFlag & setAlertingEnabled)
+ {
+ channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
+ chAccessData.alertingDisabled;
+ }
+ if (setFlag & setPrivLimit)
+ {
+ channelData[chNum].chAccess.chNonVolatileData.privLimit =
+ chAccessData.privLimit;
+ }
+
+ // Write persistent data to file
+ if (writeChannelPersistData() != 0)
+ {
+ log<level::DEBUG>("Failed to update the presist data file");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t
+ ChannelConfig::getChannelAuthTypeSupported(const uint8_t& chNum,
+ uint8_t& authTypeSupported)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t& chNum,
+ const uint8_t& priv,
+ EAuthType& authType)
+{
+ if (!isValidChannel(chNum))
+ {
+ log<level::DEBUG>("Invalid channel");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
+ {
+ log<level::DEBUG>("Sessionless channel doesn't have access data.");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ if (!isValidPrivLimit(priv))
+ {
+ log<level::DEBUG>("Invalid privilege specified.");
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+
+ // TODO: Hardcoded for now. Need to implement.
+ authType = EAuthType::none;
+
+ return IPMI_CC_OK;
+}
+
+std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
+{
+ struct stat fileStat;
+ if (stat(fileName.c_str(), &fileStat) != 0)
+ {
+ log<level::DEBUG>("Error in getting last updated time stamp");
+ return -EIO;
+ }
+ return fileStat.st_mtime;
+}
+
+EChannelAccessMode
+ ChannelConfig::convertToAccessModeIndex(const std::string& mode)
+{
+ auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
+ if (iter == accessModeList.end())
+ {
+ log<level::ERR>("Invalid access mode.",
+ entry("MODE_STR=%s", mode.c_str()));
+ throw std::invalid_argument("Invalid access mode.");
+ }
+
+ return static_cast<EChannelAccessMode>(
+ std::distance(accessModeList.begin(), iter));
+}
+
+std::string ChannelConfig::convertToAccessModeString(const uint8_t& value)
+{
+ if (accessModeList.size() <= value)
+ {
+ log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
+ throw std::invalid_argument("Invalid access mode.");
+ }
+
+ return accessModeList.at(value);
+}
+
+CommandPrivilege
+ ChannelConfig::convertToPrivLimitIndex(const std::string& value)
+{
+ auto iter = std::find(privList.begin(), privList.end(), value);
+ if (iter == privList.end())
+ {
+ log<level::ERR>("Invalid privilege.",
+ entry("PRIV_STR=%s", value.c_str()));
+ throw std::invalid_argument("Invalid privilege.");
+ }
+
+ return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
+}
+
+std::string ChannelConfig::convertToPrivLimitString(const uint8_t& value)
+{
+ if (privList.size() <= value)
+ {
+ log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
+ throw std::invalid_argument("Invalid privilege.");
+ }
+
+ return privList.at(value);
+}
+
+EChannelSessSupported
+ ChannelConfig::convertToSessionSupportIndex(const std::string& value)
+{
+ auto iter =
+ std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
+ if (iter == sessionSupportList.end())
+ {
+ log<level::ERR>("Invalid session supported.",
+ entry("SESS_STR=%s", value.c_str()));
+ throw std::invalid_argument("Invalid session supported.");
+ }
+
+ return static_cast<EChannelSessSupported>(
+ std::distance(sessionSupportList.begin(), iter));
+}
+
+EChannelMediumType
+ ChannelConfig::convertToMediumTypeIndex(const std::string& value)
+{
+ std::unordered_map<std::string, EChannelMediumType>::iterator it =
+ mediumTypeMap.find(value);
+ if (it == mediumTypeMap.end())
+ {
+ log<level::ERR>("Invalid medium type.",
+ entry("MEDIUM_STR=%s", value.c_str()));
+ throw std::invalid_argument("Invalid medium type.");
+ }
+
+ return static_cast<EChannelMediumType>(it->second);
+}
+
+EChannelProtocolType
+ ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
+{
+ std::unordered_map<std::string, EChannelProtocolType>::iterator it =
+ protocolTypeMap.find(value);
+ if (it == protocolTypeMap.end())
+ {
+ log<level::ERR>("Invalid protocol type.",
+ entry("PROTO_STR=%s", value.c_str()));
+ throw std::invalid_argument("Invalid protocol type.");
+ }
+
+ return static_cast<EChannelProtocolType>(it->second);
+}
+
+Json ChannelConfig::readJsonFile(const std::string& configFile)
+{
+ std::ifstream jsonFile(configFile);
+ if (!jsonFile.good())
+ {
+ log<level::ERR>("JSON file not found");
+ return nullptr;
+ }
+
+ Json data = nullptr;
+ try
+ {
+ data = Json::parse(jsonFile, nullptr, false);
+ }
+ catch (Json::parse_error& e)
+ {
+ log<level::DEBUG>("Corrupted channel config.",
+ entry("MSG: %s", e.what()));
+ throw std::runtime_error("Corrupted channel config file");
+ }
+
+ return data;
+}
+
+int ChannelConfig::writeJsonFile(const std::string& configFile,
+ const Json& jsonData)
+{
+ std::ofstream jsonFile(configFile);
+ if (!jsonFile.good())
+ {
+ log<level::ERR>("JSON file not found");
+ return -EIO;
+ }
+
+ // Write JSON to file
+ jsonFile << jsonData;
+
+ jsonFile.flush();
+ return 0;
+}
+
+void ChannelConfig::setDefaultChannelConfig(const uint8_t& chNum,
+ const std::string& chName)
+{
+ channelData[chNum].chName = chName;
+ channelData[chNum].chID = chNum;
+ channelData[chNum].isChValid = false;
+ channelData[chNum].activeSessCount = 0;
+
+ channelData[chNum].chInfo.mediumType = defaultMediumType;
+ channelData[chNum].chInfo.protocolType = defaultProtocolType;
+ channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
+ channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
+ channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
+}
+
+int ChannelConfig::loadChannelConfig()
+{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
+ Json data = readJsonFile(channelConfigDefaultFilename);
+ if (data == nullptr)
+ {
+ log<level::DEBUG>("Error in opening IPMI Channel data file");
+ return -EIO;
+ }
+
+ try
+ {
+ // Fill in global structure
+ for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
+ {
+ std::fill(reinterpret_cast<uint8_t*>(&channelData[chNum]),
+ reinterpret_cast<uint8_t*>(&channelData[chNum]) +
+ sizeof(ChannelData),
+ 0);
+ std::string chKey = std::to_string(chNum);
+ Json jsonChData = data[chKey].get<Json>();
+ if (jsonChData.is_null())
+ {
+ log<level::WARNING>(
+ "Channel not configured so loading default.",
+ entry("CHANNEL_NUM:%d", chNum));
+ // If user didn't want to configure specific channel (say
+ // reserved channel), then load that index with default values.
+ std::string chName(defaultChannelName);
+ setDefaultChannelConfig(chNum, chName);
+ }
+ else
+ {
+ std::string chName = jsonChData[nameString].get<std::string>();
+ channelData[chNum].chName = chName;
+ channelData[chNum].chID = chNum;
+ channelData[chNum].isChValid =
+ jsonChData[isValidString].get<bool>();
+ channelData[chNum].activeSessCount =
+ jsonChData.value(activeSessionsString, 0);
+ Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
+ if (jsonChInfo.is_null())
+ {
+ log<level::ERR>("Invalid/corrupted channel config file");
+ return -EBADMSG;
+ }
+ else
+ {
+ std::string medTypeStr =
+ jsonChInfo[mediumTypeString].get<std::string>();
+ channelData[chNum].chInfo.mediumType = static_cast<uint8_t>(
+ convertToMediumTypeIndex(medTypeStr));
+ std::string protoTypeStr =
+ jsonChInfo[protocolTypeString].get<std::string>();
+ channelData[chNum].chInfo.protocolType =
+ static_cast<uint8_t>(
+ convertToProtocolTypeIndex(protoTypeStr));
+ std::string sessStr =
+ jsonChInfo[sessionSupportedString].get<std::string>();
+ channelData[chNum].chInfo.sessionSupported =
+ static_cast<uint8_t>(
+ convertToSessionSupportIndex(sessStr));
+ channelData[chNum].chInfo.isIpmi =
+ jsonChInfo[isIpmiString].get<bool>();
+ channelData[chNum].chInfo.authTypeSupported =
+ defaultAuthType;
+ }
+ }
+ }
+ }
+ catch (const Json::exception& e)
+ {
+ log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
+ return -EBADMSG;
+ }
+ catch (const std::invalid_argument& e)
+ {
+ log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+int ChannelConfig::readChannelVolatileData()
+{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
+ Json data = readJsonFile(channelVolatileDataFilename);
+ if (data == nullptr)
+ {
+ log<level::DEBUG>("Error in opening IPMI Channel data file");
+ return -EIO;
+ }
+
+ try
+ {
+ // Fill in global structure
+ for (auto it = data.begin(); it != data.end(); ++it)
+ {
+ std::string chKey = it.key();
+ uint8_t chNum = std::stoi(chKey, nullptr, 10);
+ if ((chNum < 0) || (chNum > maxIpmiChannels))
+ {
+ log<level::DEBUG>(
+ "Invalid channel access entry in config file");
+ throw std::out_of_range("Out of range - channel number");
+ }
+ Json jsonChData = it.value();
+ if (!jsonChData.is_null())
+ {
+ std::string accModeStr =
+ jsonChData[accessModeString].get<std::string>();
+ channelData[chNum].chAccess.chVolatileData.accessMode =
+ static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
+ channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
+ jsonChData[userAuthDisabledString].get<bool>();
+ channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
+ jsonChData[perMsgAuthDisabledString].get<bool>();
+ channelData[chNum].chAccess.chVolatileData.alertingDisabled =
+ jsonChData[alertingDisabledString].get<bool>();
+ std::string privStr =
+ jsonChData[privLimitString].get<std::string>();
+ channelData[chNum].chAccess.chVolatileData.privLimit =
+ static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
+ }
+ else
+ {
+ log<level::ERR>(
+ "Invalid/corrupted volatile channel access file",
+ entry("FILE: %s", channelVolatileDataFilename));
+ throw std::runtime_error(
+ "Corrupted volatile channel access file");
+ }
+ }
+ }
+ catch (const Json::exception& e)
+ {
+ log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
+ throw std::runtime_error("Corrupted volatile channel access file");
+ }
+ catch (const std::invalid_argument& e)
+ {
+ log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
+ throw std::runtime_error("Corrupted volatile channel access file");
+ }
+
+ // Update the timestamp
+ voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
+ return 0;
+}
+
+int ChannelConfig::readChannelPersistData()
+{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
+ Json data = readJsonFile(channelNvDataFilename);
+ if (data == nullptr)
+ {
+ log<level::DEBUG>("Error in opening IPMI Channel data file");
+ return -EIO;
+ }
+
+ try
+ {
+ // Fill in global structure
+ for (auto it = data.begin(); it != data.end(); ++it)
+ {
+ std::string chKey = it.key();
+ uint8_t chNum = std::stoi(chKey, nullptr, 10);
+ if ((chNum < 0) || (chNum > maxIpmiChannels))
+ {
+ log<level::DEBUG>(
+ "Invalid channel access entry in config file");
+ throw std::out_of_range("Out of range - channel number");
+ }
+ Json jsonChData = it.value();
+ if (!jsonChData.is_null())
+ {
+ std::string accModeStr =
+ jsonChData[accessModeString].get<std::string>();
+ channelData[chNum].chAccess.chNonVolatileData.accessMode =
+ static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
+ channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
+ jsonChData[userAuthDisabledString].get<bool>();
+ channelData[chNum]
+ .chAccess.chNonVolatileData.perMsgAuthDisabled =
+ jsonChData[perMsgAuthDisabledString].get<bool>();
+ channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
+ jsonChData[alertingDisabledString].get<bool>();
+ std::string privStr =
+ jsonChData[privLimitString].get<std::string>();
+ channelData[chNum].chAccess.chNonVolatileData.privLimit =
+ static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
+ }
+ else
+ {
+ log<level::ERR>("Invalid/corrupted nv channel access file",
+ entry("FILE:%s", channelNvDataFilename));
+ throw std::runtime_error("Corrupted nv channel access file");
+ }
+ }
+ }
+ catch (const Json::exception& e)
+ {
+ log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
+ throw std::runtime_error("Corrupted nv channel access file");
+ }
+ catch (const std::invalid_argument& e)
+ {
+ log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ throw std::runtime_error("Corrupted nv channel access file");
+ }
+
+ // Update the timestamp
+ nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
+ return 0;
+}
+
+int ChannelConfig::writeChannelVolatileData()
+{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+ Json outData;
+
+ try
+ {
+ for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
+ {
+ if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
+ {
+ Json jsonObj;
+ std::string chKey = std::to_string(chNum);
+ std::string accModeStr = convertToAccessModeString(
+ channelData[chNum].chAccess.chVolatileData.accessMode);
+ jsonObj[accessModeString] = accModeStr;
+ jsonObj[userAuthDisabledString] =
+ channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
+ jsonObj[perMsgAuthDisabledString] =
+ channelData[chNum]
+ .chAccess.chVolatileData.perMsgAuthDisabled;
+ jsonObj[alertingDisabledString] =
+ channelData[chNum].chAccess.chVolatileData.alertingDisabled;
+ std::string privStr = convertToPrivLimitString(
+ channelData[chNum].chAccess.chVolatileData.privLimit);
+ jsonObj[privLimitString] = privStr;
+
+ outData[chKey] = jsonObj;
+ }
+ }
+ }
+ catch (const std::invalid_argument& e)
+ {
+ log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ return -EINVAL;
+ }
+
+ if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
+ {
+ log<level::DEBUG>("Error in write JSON data to file");
+ return -EIO;
+ }
+
+ // Update the timestamp
+ voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
+ return 0;
+}
+
+int ChannelConfig::writeChannelPersistData()
+{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+ Json outData;
+
+ try
+ {
+ for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
+ {
+ if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
+ {
+ Json jsonObj;
+ std::string chKey = std::to_string(chNum);
+ std::string accModeStr = convertToAccessModeString(
+ channelData[chNum].chAccess.chNonVolatileData.accessMode);
+ jsonObj[accessModeString] = accModeStr;
+ jsonObj[userAuthDisabledString] =
+ channelData[chNum]
+ .chAccess.chNonVolatileData.userAuthDisabled;
+ jsonObj[perMsgAuthDisabledString] =
+ channelData[chNum]
+ .chAccess.chNonVolatileData.perMsgAuthDisabled;
+ jsonObj[alertingDisabledString] =
+ channelData[chNum]
+ .chAccess.chNonVolatileData.alertingDisabled;
+ std::string privStr = convertToPrivLimitString(
+ channelData[chNum].chAccess.chNonVolatileData.privLimit);
+ jsonObj[privLimitString] = privStr;
+
+ outData[chKey] = jsonObj;
+ }
+ }
+ }
+ catch (const std::invalid_argument& e)
+ {
+ log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ return -EINVAL;
+ }
+
+ if (writeJsonFile(channelNvDataFilename, outData) != 0)
+ {
+ log<level::DEBUG>("Error in write JSON data to file");
+ return -EIO;
+ }
+
+ // Update the timestamp
+ nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
+ return 0;
+}
+
+int ChannelConfig::checkAndReloadNVData()
+{
+ std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
+ int ret = 0;
+ if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
+ {
+ try
+ {
+ ret = readChannelPersistData();
+ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>("Exception caught in readChannelPersistData.",
+ entry("MSG=%s", e.what()));
+ ret = -EIO;
+ }
+ }
+ return ret;
+}
+
+int ChannelConfig::checkAndReloadVolatileData()
+{
+ std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
+ int ret = 0;
+ if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
+ {
+ try
+ {
+ ret = readChannelVolatileData();
+ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>("Exception caught in readChannelVolatileData.",
+ entry("MSG=%s", e.what()));
+ ret = -EIO;
+ }
+ }
+ return ret;
+}
+
+void ChannelConfig::initChannelPersistData()
+{
+ /* Always read the channel config */
+ if (loadChannelConfig() != 0)
+ {
+ log<level::ERR>("Failed to read channel config file");
+ throw std::ios_base::failure("Failed to load channel configuration");
+ }
+
+ /* Populate the channel persist data */
+ if (readChannelPersistData() != 0)
+ {
+ // Copy default NV data to RW location
+ std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
+ channelNvDataFilename);
+
+ // Load the channel access NV data
+ if (readChannelPersistData() != 0)
+ {
+ log<level::ERR>("Failed to read channel access NV data");
+ throw std::ios_base::failure(
+ "Failed to read channel access NV configuration");
+ }
+ }
+
+ // First check the volatile data file
+ // If not present, load the default values
+ if (readChannelVolatileData() != 0)
+ {
+ // Copy default volatile data to temporary location
+ // NV file(channelNvDataFilename) must have created by now.
+ std::experimental::filesystem::copy_file(channelNvDataFilename,
+ channelVolatileDataFilename);
+
+ // Load the channel access volatile data
+ if (readChannelVolatileData() != 0)
+ {
+ log<level::ERR>("Failed to read channel access volatile data");
+ throw std::ios_base::failure(
+ "Failed to read channel access volatile configuration");
+ }
+ }
+ return;
+}
+
+} // namespace ipmi
OpenPOWER on IntegriCloud