Updated the close session to close any session
Added support in close session command to close not only the self
sessions but also other netipmid sessions.
With this support, now any netipmid instance will be able to close
any other netipmid instance's session.
Tested close session command for both self and other netipmid sessions:
Unit Tested:
Close the existing valid session by session id
ipmitool raw 0x6 0x3c <valid sesssion id >
Response : 00 // success
Close the existing valid session by session handle
ipmitool raw 0x6 0x3c <zero session id> <valid session handle>
Response : 00 // success
Close the session by zero session id
ipmitool raw 0x6 0x3c <zero session id>
Response : 0x87 // Inavlid Session Id
Close the session by zero session handle
ipmitool raw 0x6 0x3c <zero session id> <zero session handle>
Response : 0x88 // inavlid session handle
Close an inactive session.
ipmitool raw 0x6 0x3c <valid session id>
Response : 0xcc // invalid data field in request
Close an inactive session.
ipmitool raw 0x6 0x3c <zero session id> <valid session handle>
Response : 0xcc // invalid data field in request
Close high privilege session by session id.
ipmitool raw 0x6 0x3c <valid session id>
Response : 0xd4 // insufficient privilege level
Close high privilege session by session handle.
ipmitool raw 0x6 0x3c <zero session id> <valid session handle>
Response : 0xd4 // insufficient privilege level
Signed-off-by: Rajashekar Gade Reddy <raja.sekhar.reddy.gade@linux.intel.com>
Change-Id: Ieade8e342777a940d30248bb23f67dc3c787a001
diff --git a/command/session_cmds.cpp b/command/session_cmds.cpp
index 52eb02f..a08e8f2 100644
--- a/command/session_cmds.cpp
+++ b/command/session_cmds.cpp
@@ -5,8 +5,13 @@
#include <ipmid/api.h>
+#include <ipmid/sessionhelper.hpp>
+#include <ipmid/utils.hpp>
+#include <phosphor-logging/log.hpp>
+
namespace command
{
+using namespace phosphor::logging;
std::vector<uint8_t>
setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
@@ -62,6 +67,143 @@
return outPayload;
}
+/**
+ * @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;
+}
+
+uint8_t closeOtherNetInstanceSession(const uint32_t reqSessionId,
+ const uint8_t reqSessionHandle,
+ const uint8_t currentSessionPriv)
+{
+ auto busp = getSdBus();
+
+ 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;
+
+ if (serviceMap.size() != 1)
+ {
+ return ipmi::ccUnspecifiedError;
+ }
+
+ auto itr = serviceMap.begin();
+ const std::string service = itr->first;
+ uint8_t closeSessionPriv =
+ std::get<uint8_t>(ipmi::getDbusProperty(
+ *busp, service, obj, session::sessionIntf,
+ "CurrentPrivilege"));
+
+ if (currentSessionPriv < closeSessionPriv)
+ {
+ return ipmi::ccInsufficientPrivilege;
+ }
+ return 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::ccUnspecifiedError;
+ }
+
+ return ipmi::ccInvalidFieldRequest;
+}
+
+uint8_t closeMyNetInstanceSession(uint32_t reqSessionId,
+ uint8_t reqSessionHandle,
+ const uint8_t currentSessionPriv)
+{
+ bool status = false;
+
+ try
+ {
+ if (reqSessionId == session::sessionZero)
+ {
+ reqSessionId = std::get<session::Manager&>(singletonPool)
+ .getSessionIDbyHandle(
+ reqSessionHandle &
+ session::multiIntfaceSessionHandleMask);
+ if (!reqSessionId)
+ {
+ return session::ccInvalidSessionHandle;
+ }
+ }
+
+ auto closeSessionInstance =
+ std::get<session::Manager&>(singletonPool).getSession(reqSessionId);
+ uint8_t closeSessionPriv = closeSessionInstance->currentPrivilege();
+
+ if (currentSessionPriv < closeSessionPriv)
+ {
+ return ipmi::ccInsufficientPrivilege;
+ }
+ status = std::get<session::Manager&>(singletonPool)
+ .stopSession(reqSessionId);
+
+ if (!status)
+ {
+ return session::ccInvalidSessionId;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Failed to get session manager instance",
+ entry("ERRMSG=%s", e.what()));
+ return ipmi::ccUnspecifiedError;
+ }
+
+ return ipmi::ccSuccess;
+}
+
std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload,
const message::Handler& handler)
{
@@ -69,25 +211,64 @@
auto request =
reinterpret_cast<const CloseSessionRequest*>(inPayload.data());
auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data());
- response->completionCode = IPMI_CC_OK;
+ uint32_t reqSessionId = request->sessionID;
+ uint8_t ipmiNetworkInstance = 0;
+ uint8_t currentSessionPriv = 0;
+ uint8_t reqSessionHandle = request->sessionHandle;
- auto bmcSessionID = endian::from_ipmi(request->sessionID);
-
- // Session 0 is needed to handle session setup, so session zero is never
- // closed
- if (bmcSessionID == session::sessionZero)
+ if (reqSessionId == session::sessionZero &&
+ reqSessionHandle == session::invalidSessionHandle)
{
- response->completionCode = IPMI_CC_INVALID_SESSIONID;
+ response->completionCode = session::ccInvalidSessionHandle;
+ return outPayload;
+ }
+
+ if (inPayload.size() == sizeof(reqSessionId) &&
+ reqSessionId == session::sessionZero)
+ {
+ response->completionCode = session::ccInvalidSessionId;
+ return outPayload;
+ }
+
+ if (reqSessionId != session::sessionZero &&
+ inPayload.size() != sizeof(reqSessionId))
+ {
+ response->completionCode = ipmi::ccInvalidFieldRequest;
+ return outPayload;
+ }
+
+ try
+ {
+ ipmiNetworkInstance =
+ std::get<session::Manager&>(singletonPool).getNetworkInstance();
+ auto currentSession = std::get<session::Manager&>(singletonPool)
+ .getSession(handler.sessionID);
+ currentSessionPriv = currentSession->currentPrivilege();
+ }
+ catch (sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("Failed to fetch object from dbus",
+ entry("INTERFACE=%s", session::sessionIntf),
+ entry("ERRMSG=%s", e.what()));
+ response->completionCode = ipmi::ccUnspecifiedError;
+ return outPayload;
+ }
+
+ if (reqSessionId >> myNetInstanceSessionIdShiftMask ==
+ ipmiNetworkInstance ||
+ (reqSessionId == session::sessionZero &&
+ (reqSessionHandle >> myNetInstanceSessionHandleShiftMask ==
+ ipmiNetworkInstance)))
+ {
+ response->completionCode = closeMyNetInstanceSession(
+ reqSessionId, reqSessionHandle, currentSessionPriv);
}
else
{
- auto status = std::get<session::Manager&>(singletonPool)
- .stopSession(bmcSessionID);
- if (!status)
- {
- response->completionCode = IPMI_CC_INVALID_SESSIONID;
- }
+ response->completionCode = closeOtherNetInstanceSession(
+ reqSessionId, reqSessionHandle, currentSessionPriv);
}
+
return outPayload;
}
diff --git a/command/session_cmds.hpp b/command/session_cmds.hpp
index 9737fdb..d5d394b 100644
--- a/command/session_cmds.hpp
+++ b/command/session_cmds.hpp
@@ -9,6 +9,10 @@
constexpr uint8_t IPMI_CC_INVALID_PRIV_LEVEL = 0x80;
constexpr uint8_t IPMI_CC_EXCEEDS_USER_PRIV = 0x81;
+// bits 30 & 31 (MSB) hold the instanceID, hence shifting by 30 bits
+constexpr uint8_t myNetInstanceSessionIdShiftMask = 30;
+// bits 6 & 7 (MSB) hold the instanceID, hence shifting by 6 bits
+constexpr uint8_t myNetInstanceSessionHandleShiftMask = 6;
/**
* @struct SetSessionPrivLevelReq
@@ -74,9 +78,6 @@
std::vector<uint8_t>
setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
const message::Handler& handler);
-
-constexpr uint8_t IPMI_CC_INVALID_SESSIONID = 0x87;
-
/**
* @struct CloseSessionRequest
*