summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apphandler.cpp112
-rw-r--r--include/Makefile.am1
-rw-r--r--include/ipmid/sessiondef.hpp3
-rw-r--r--include/ipmid/sessionhelper.hpp88
-rw-r--r--test/Makefile.am18
-rw-r--r--test/session/closesession_unittest.cpp114
6 files changed, 336 insertions, 0 deletions
diff --git a/apphandler.cpp b/apphandler.cpp
index c5a608d..0c8eb92 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -20,6 +20,8 @@
#include <filesystem>
#include <fstream>
#include <ipmid/api.hpp>
+#include <ipmid/sessiondef.hpp>
+#include <ipmid/sessionhelper.hpp>
#include <ipmid/types.hpp>
#include <ipmid/utils.hpp>
#include <memory>
@@ -842,6 +844,112 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
return ipmi::responseSuccess(uuid);
}
+/**
+ * @brief set the session state as teardown
+ *
+ * This function is to set the session state to tear down in progress if the
+ * state is active.
+ *
+ * @param[in] busp - Dbus obj
+ * @param[in] service - service name
+ * @param[in] obj - object path
+ *
+ * @return success completion code if it sets the session state to
+ * tearDownInProgress else return the corresponding error completion code.
+ **/
+uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
+ const std::string& service, const std::string& obj)
+{
+ try
+ {
+ uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
+ *busp, service, obj, session::sessionIntf, "State"));
+
+ if (sessionState == static_cast<uint8_t>(session::State::active))
+ {
+ ipmi::setDbusProperty(
+ *busp, service, obj, session::sessionIntf, "State",
+ static_cast<uint8_t>(session::State::tearDownInProgress));
+ return ipmi::ccSuccess;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Failed in getting session state property",
+ entry("service=%s", service.c_str()),
+ entry("object path=%s", obj.c_str()),
+ entry("interface=%s", session::sessionIntf));
+ return ipmi::ccUnspecifiedError;
+ }
+
+ return ipmi::ccInvalidFieldRequest;
+}
+
+ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId,
+ std::optional<uint8_t> requestSessionHandle)
+{
+ auto busp = getSdBus();
+ uint8_t reqSessionHandle =
+ requestSessionHandle.value_or(session::defaultSessionHandle);
+
+ if (reqSessionId == session::sessionZero &&
+ reqSessionHandle == session::defaultSessionHandle)
+ {
+ return ipmi::response(session::ccInvalidSessionId);
+ }
+
+ if (reqSessionId == session::sessionZero &&
+ reqSessionHandle == session::invalidSessionHandle)
+ {
+ return ipmi::response(session::ccInvalidSessionHandle);
+ }
+
+ if (reqSessionId != session::sessionZero &&
+ reqSessionHandle != session::defaultSessionHandle)
+ {
+ return ipmi::response(ipmi::ccInvalidFieldRequest);
+ }
+
+ try
+ {
+ ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
+ *busp, session::sessionManagerRootPath, session::sessionIntf);
+
+ for (auto& objectTreeItr : objectTree)
+ {
+ const std::string obj = objectTreeItr.first;
+
+ if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
+ {
+ auto& serviceMap = objectTreeItr.second;
+
+ // Session id and session handle are unique for each session.
+ // Session id and handler are retrived from the object path and
+ // object path will be unique for each session. Checking if
+ // multiple objects exist with same object path under multiple
+ // services.
+ if (serviceMap.size() != 1)
+ {
+ return ipmi::responseUnspecifiedError();
+ }
+
+ auto itr = serviceMap.begin();
+ const std::string service = itr->first;
+ return ipmi::response(setSessionState(busp, service, obj));
+ }
+ }
+ }
+ catch (sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("Failed to fetch object from dbus",
+ entry("INTERFACE=%s", session::sessionIntf),
+ entry("ERRMSG=%s", e.what()));
+ return ipmi::responseUnspecifiedError();
+ }
+
+ return ipmi::responseInvalidFieldRequest();
+}
+
static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
static std::string sysInfoReadSystemName()
@@ -1175,6 +1283,10 @@ void register_netfn_app_functions()
ipmi::app::cmdSetWatchdogTimer,
ipmi::Privilege::Operator, ipmiSetWatchdogTimer);
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
+ ipmi::app::cmdCloseSession, ipmi::Privilege::Callback,
+ ipmiAppCloseSession);
+
// <Get Watchdog Timer>
ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
ipmi::app::cmdGetWatchdogTimer,
diff --git a/include/Makefile.am b/include/Makefile.am
index 996c41a..08824c4 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -2,6 +2,7 @@ nobase_include_HEADERS = \
ipmid/api.hpp \
ipmid/api-types.hpp \
ipmid/sessiondef.hpp \
+ ipmid/sessionhelper.hpp \
ipmid/filter.hpp \
ipmid/handler.hpp \
ipmid/message.hpp \
diff --git a/include/ipmid/sessiondef.hpp b/include/ipmid/sessiondef.hpp
index 9fce256..48ee4c6 100644
--- a/include/ipmid/sessiondef.hpp
+++ b/include/ipmid/sessiondef.hpp
@@ -28,7 +28,10 @@ static constexpr size_t sessionZero = 0;
static constexpr size_t maxSessionlessCount = 1;
static constexpr uint8_t invalidSessionID = 0;
static constexpr uint8_t invalidSessionHandle = 0;
+static constexpr uint8_t defaultSessionHandle = 0xFF;
static constexpr uint8_t maxNetworkInstanceSupported = 4;
+static constexpr uint8_t ccInvalidSessionId = 0x87;
+static constexpr uint8_t ccInvalidSessionHandle = 0x88;
// MSB BIT 7 BIT 6 assigned for netipmid instance in session handle.
static constexpr uint8_t multiIntfaceSessionHandleMask = 0x3F;
diff --git a/include/ipmid/sessionhelper.hpp b/include/ipmid/sessionhelper.hpp
new file mode 100644
index 0000000..a96f037
--- /dev/null
+++ b/include/ipmid/sessionhelper.hpp
@@ -0,0 +1,88 @@
+#include <sstream>
+#include <string>
+
+/**
+ * @brief parse session input payload.
+ *
+ * This function retrives the session id and session handle from the session
+ * object path.
+ * A valid object path will be in the form
+ * "/xyz/openbmc_project/ipmi/session/channel/sessionId_sessionHandle"
+ *
+ * Ex: "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"
+ * SessionId : 0X12a4567d
+ * SessionHandle: 0X8a
+
+ * @param[in] objectPath - session object path
+ * @param[in] sessionId - retrived session id will be asigned.
+ * @param[in] sessionHandle - retrived session handle will be asigned.
+ *
+ * @return true if session id and session handle are retrived else returns
+ * false.
+ */
+bool parseCloseSessionInputPayload(const std::string& objectPath,
+ uint32_t& sessionId, uint8_t& sessionHandle)
+{
+ if (objectPath.empty())
+ {
+ return false;
+ }
+ // getting the position of session id and session handle string from
+ // object path.
+ std::size_t ptrPosition = objectPath.rfind("/");
+ uint16_t tempSessionHandle = 0;
+
+ if (ptrPosition != std::string::npos)
+ {
+ // get the sessionid & session handle string from the session object
+ // path Ex: sessionIdString: "12a4567d_8a"
+ std::string sessionIdString = objectPath.substr(ptrPosition + 1);
+ std::size_t pos = sessionIdString.rfind("_");
+
+ if (pos != std::string::npos)
+ {
+ // extracting the session handle
+ std::string sessionHandleString = sessionIdString.substr(pos + 1);
+ // extracting the session id
+ sessionIdString = sessionIdString.substr(0, pos);
+ // converting session id string and session handle string to
+ // hexadecimal.
+ std::stringstream handle(sessionHandleString);
+ handle >> std::hex >> tempSessionHandle;
+ sessionHandle = tempSessionHandle & 0xFF;
+ std::stringstream idString(sessionIdString);
+ idString >> std::hex >> sessionId;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * @brief is session object matched.
+ *
+ * This function checks whether the objectPath contains reqSessionId and
+ * reqSessionHandle, e.g., "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"
+ * matches sessionId 0x12a4567d and sessionHandle 0x8a.
+ *
+ * @param[in] objectPath - session object path
+ * @param[in] reqSessionId - request session id
+ * @param[in] reqSessionHandle - request session handle
+ *
+ * @return true if the object is matched else return false
+ **/
+bool isSessionObjectMatched(const std::string objectPath,
+ const uint32_t reqSessionId,
+ const uint8_t reqSessionHandle)
+{
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0;
+
+ if (parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle))
+ {
+ return (reqSessionId == sessionId) ||
+ (reqSessionHandle == sessionHandle);
+ }
+
+ return false;
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index e4ff261..0faeda7 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -72,3 +72,21 @@ message_unittest_SOURCES = \
%reldir%/message/unpack.cpp \
%reldir%/message/pack.cpp
check_PROGRAMS += %reldir%/message_unittest
+
+# Build/add closesession_unittest to test suite
+session_unittest_CPPFLAGS = \
+ -Igtest \
+ $(GTEST_CPPFLAGS) \
+ $(AM_CPPFLAGS)
+session_unittest_CXXFLAGS = \
+ $(PTHREAD_CFLAGS) \
+ $(CODE_COVERAGE_CXXFLAGS) \
+ $(CODE_COVERAGE_CFLAGS)
+session_unittest_LDFLAGS = \
+ -lgtest_main \
+ -lgtest \
+ -pthread \
+ $(OESDK_TESTCASE_FLAGS) \
+ $(CODE_COVERAGE_LDFLAGS)
+session_unittest_SOURCES = %reldir%/session/closesession_unittest.cpp
+check_PROGRAMS += %reldir%/session_unittest
diff --git a/test/session/closesession_unittest.cpp b/test/session/closesession_unittest.cpp
new file mode 100644
index 0000000..2b184ca
--- /dev/null
+++ b/test/session/closesession_unittest.cpp
@@ -0,0 +1,114 @@
+#include <ipmid/sessionhelper.hpp>
+
+#include <gtest/gtest.h>
+
+TEST(parseSessionInputPayloadTest, ValidObjectPath)
+{
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0;
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+
+ EXPECT_TRUE(
+ parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle));
+ EXPECT_EQ(0x12a4567d, sessionId);
+ EXPECT_EQ(0x8a, sessionHandle);
+}
+
+TEST(parseSessionInputPayloadTest, InvalidObjectPath)
+{
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0;
+ // A valid object path will be like
+ // "/xyz/openbmc_project/ipmi/session/channel/sessionId_sessionHandle"
+ // Ex: "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"
+ // SessionId : 0X12a4567d
+ // SessionHandle: 0X8a
+ std::string objectPath = "/xyz/openbmc_project/ipmi/session/eth0/12a4567d";
+
+ EXPECT_FALSE(
+ parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle));
+}
+
+TEST(parseSessionInputPayloadTest, NoObjectPath)
+{
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0;
+ std::string objectPath;
+
+ EXPECT_FALSE(
+ parseCloseSessionInputPayload(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, ValidSessionId)
+{
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+ uint32_t sessionId = 0x12a4567d;
+ uint8_t sessionHandle = 0;
+
+ EXPECT_TRUE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, ValidSessionHandle)
+{
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0x8a;
+
+ EXPECT_TRUE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, InvalidSessionId)
+{
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+ uint32_t sessionId = 0x1234b67d;
+ uint8_t sessionHandle = 0;
+
+ EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, InvalidSessionHandle)
+{
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0x9b;
+
+ EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, ZeroSessionId_ZeroSessionHandle)
+{
+ std::string objectPath =
+ "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a";
+ uint32_t sessionId = 0;
+ uint8_t sessionHandle = 0;
+
+ EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, InvalidObjectPath)
+{
+ // A valid object path will be like
+ // "/xyz/openbmc_project/ipmi/session/channel/sessionId_sessionHandle"
+ // Ex: "/xyz/openbmc_project/ipmi/session/eth0/12a4567d_8a"
+ // SessionId : 0X12a4567d
+ // SessionHandle: 0X8a
+ std::string objectPath = "/xyz/openbmc_project/ipmi/session/eth0/12a4567d";
+ uint32_t sessionId = 0x12a4567d;
+ uint8_t sessionHandle = 0;
+
+ EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
+
+TEST(isSessionObjectMatchedTest, NoObjectPath)
+{
+ std::string objectPath;
+ uint32_t sessionId = 0x12a4567d;
+ uint8_t sessionHandle = 0x8a;
+
+ EXPECT_FALSE(isSessionObjectMatched(objectPath, sessionId, sessionHandle));
+}
OpenPOWER on IntegriCloud