netipmid: Manage and expose session object

Session (RMCP+) is managed by net-ipmid directly, but
session commands has to be supported in both LAN & other
session-less interfaces. In order to make session commands
to work in other interfaces, session objects must be
exposed as D-Bus objects, so that ipmi-providers can
query the same.

Tested:
 1. Verified that RMCP+ session are perfectly working
 2. Verified RMCP+ session establishment fails for wrong
    password
 3. Verified that session privilege level are maintained
    and access are restricted accordingly
 4. Verified session timeout and sessions are destroyed
    accordingly after timeout
 5. verified max session count working behavior
 6. verified ipmi-providers responding with proper response for this
    (or D-Bus objects are exposed correctly during session creation,
    session deletion,session update,
    (like privilege, - say even set session privilege level command)
 7.Session objects are created dynamically.

Change-Id: I78a8449359877ef6cc4cd8161d8c67e6e54eb52b
Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
diff --git a/sessions_manager.cpp b/sessions_manager.cpp
index 95a8a15..a8e2361 100644
--- a/sessions_manager.cpp
+++ b/sessions_manager.cpp
@@ -1,5 +1,6 @@
 #include "sessions_manager.hpp"
 
+#include "main.hpp"
 #include "session.hpp"
 
 #include <algorithm>
@@ -7,21 +8,75 @@
 #include <iomanip>
 #include <memory>
 #include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <user_channel/channel_layer.hpp>
 
 using namespace phosphor::logging;
 
 namespace session
 {
 
+static std::array<uint8_t, session::maxNetworkInstanceSupported>
+    ipmiNetworkChannelNumList = {0};
+
+void Manager::setNetworkInstance(void)
+{
+
+    uint8_t index = 0, ch = 1;
+    // Constructing net-ipmid instances list based on channel info
+    // valid channel start from 1 to 15  and assuming max 4 LAN channel
+    // supported
+
+    while (ch < ipmi::maxIpmiChannels &&
+           index < session::maxNetworkInstanceSupported)
+    {
+        ipmi::ChannelInfo chInfo;
+        ipmi::getChannelInfo(ch, chInfo);
+        if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
+            ipmi::EChannelMediumType::lan8032)
+        {
+
+            if (getInterfaceIndex() == ch)
+            {
+                ipmiNetworkInstance = index;
+            }
+
+            ipmiNetworkChannelNumList[index] = ch;
+            index++;
+        }
+        ch++;
+    }
+}
+
+uint8_t Manager::getNetworkInstance(void)
+{
+    return ipmiNetworkInstance;
+}
+
 Manager::Manager()
 {
+}
+
+void Manager::managerInit(const std::string& channel)
+{
+
     /*
      * Session ID is 0000_0000h for messages that are sent outside the session.
      * The session setup commands are sent on this session, so when the session
      * manager comes up, is creates the Session ID  0000_0000h. It is active
      * through the lifetime of the Session Manager.
      */
-    sessionsMap.emplace(0, std::make_shared<Session>());
+
+    objManager = std::make_unique<sdbusplus::server::manager::manager>(
+        *getSdBus(), session::sessionManagerRootPath);
+
+    auto objPath =
+        std::string(session::sessionManagerRootPath) + "/" + channel + "/0";
+
+    chName = channel;
+    setNetworkInstance();
+    sessionsMap.emplace(
+        0, std::make_shared<Session>(*getSdBus(), objPath.c_str(), 0, 0, 0));
 }
 
 std::shared_ptr<Session>
@@ -31,16 +86,20 @@
                           cipher::crypt::Algorithms cryptAlgo)
 {
     std::shared_ptr<Session> session = nullptr;
-    SessionID sessionID = 0;
+    SessionID bmcSessionID = 0;
     cleanStaleEntries();
-    auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT;
+    uint8_t sessionHandle = 0;
 
-    if (activeSessions < MAX_SESSION_COUNT)
+    auto activeSessions = sessionsMap.size() - session::maxSessionlessCount;
+
+    if (activeSessions < session::maxSessionCountPerChannel)
     {
         do
         {
-            session = std::make_shared<Session>(remoteConsoleSessID, priv);
-
+            bmcSessionID = (crypto::prng::rand());
+            bmcSessionID &= session::multiIntfaceSessionIDMask;
+            // In sessionID , BIT 31 BIT30 are used for netipmid instance
+            bmcSessionID |= ipmiNetworkInstance << 30;
             /*
              * Every IPMI Session has two ID's attached to it Remote Console
              * Session ID and BMC Session ID. The remote console ID is passed
@@ -51,11 +110,10 @@
              * created session is reset and a new session is created for
              * validating collision.
              */
-            auto iterator = sessionsMap.find(session->getBMCSessionID());
+            auto iterator = sessionsMap.find(bmcSessionID);
             if (iterator != sessionsMap.end())
             {
                 // Detected BMC Session ID collisions
-                session.reset();
                 continue;
             }
             else
@@ -64,6 +122,26 @@
             }
         } while (1);
 
+        sessionHandle = storeSessionHandle(bmcSessionID);
+
+        if (!sessionHandle)
+        {
+            throw std::runtime_error(
+                "Invalid sessionHandle - No sessionID slot ");
+        }
+        sessionHandle &= session::multiIntfaceSessionHandleMask;
+        // In sessionID , BIT 31 BIT30 are used for netipmid instance
+        sessionHandle |= ipmiNetworkInstance << 6;
+        std::stringstream sstream;
+        sstream << std::hex << bmcSessionID;
+        std::stringstream shstream;
+        shstream << std::hex << (int)sessionHandle;
+        auto objPath = std::string(session::sessionManagerRootPath) + "/" +
+                       chName + "/" + sstream.str() + "_" + shstream.str();
+        session = std::make_shared<Session>(*getSdBus(), objPath.c_str(),
+                                            remoteConsoleSessID, bmcSessionID,
+                                            static_cast<uint8_t>(priv));
+
         // Set the Authentication Algorithm
         switch (authAlgo)
         {
@@ -86,8 +164,10 @@
                 throw std::runtime_error("Invalid Authentication Algorithm");
             }
         }
-        sessionID = session->getBMCSessionID();
-        sessionsMap.emplace(sessionID, session);
+
+        sessionsMap.emplace(bmcSessionID, session);
+        session->sessionHandle(sessionHandle);
+
         return session;
     }
 
@@ -101,7 +181,8 @@
     auto iter = sessionsMap.find(bmcSessionID);
     if (iter != sessionsMap.end())
     {
-        iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
+        iter->second->state(
+            static_cast<uint8_t>(session::State::tearDownInProgress));
         return true;
     }
     else
@@ -151,10 +232,12 @@
 {
     for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
     {
+
         auto session = iter->second;
-        if ((session->getBMCSessionID() != SESSION_ZERO) &&
-            !(session->isSessionActive()))
+        if ((session->getBMCSessionID() != session::sessionZero) &&
+            !(session->isSessionActive(session->state())))
         {
+            sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0;
             iter = sessionsMap.erase(iter);
         }
         else
@@ -164,4 +247,54 @@
     }
 }
 
+uint8_t Manager::storeSessionHandle(SessionID bmcSessionID)
+{
+    // Handler index 0 is  reserved for invalid session.
+    // index starts with 1, for direct usage. Index 0 reserved
+    for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++)
+    {
+        if (sessionHandleMap[i] == 0)
+        {
+            sessionHandleMap[i] = bmcSessionID;
+            return i;
+        }
+    }
+    return 0;
+}
+
+uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const
+{
+    if (sessionHandle <= session::maxSessionCountPerChannel)
+    {
+        return sessionHandleMap[sessionHandle];
+    }
+    return 0;
+}
+
+uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const
+{
+
+    // Handler index 0 is reserved for invalid session.
+    // index starts with 1, for direct usage. Index 0 reserved
+
+    for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++)
+    {
+        if (sessionHandleMap[i] == bmcSessionID)
+        {
+            return (i);
+        }
+    }
+    return 0;
+}
+uint8_t Manager::getActiveSessionCount() const
+{
+
+    return (std::count_if(
+        sessionsMap.begin(), sessionsMap.end(),
+        [](const std::pair<const uint32_t, std::shared_ptr<Session>>& in)
+            -> bool {
+            return in.second->state() ==
+                   static_cast<uint8_t>(session::State::active);
+        }));
+}
 } // namespace session