blob: 95a8a15c04accdcbed29df396f268d178571c1c6 [file] [log] [blame]
#include "sessions_manager.hpp"
#include "session.hpp"
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <memory>
#include <phosphor-logging/log.hpp>
using namespace phosphor::logging;
namespace session
{
Manager::Manager()
{
/*
* 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>());
}
std::shared_ptr<Session>
Manager::startSession(SessionID remoteConsoleSessID, Privilege priv,
cipher::rakp_auth::Algorithms authAlgo,
cipher::integrity::Algorithms intAlgo,
cipher::crypt::Algorithms cryptAlgo)
{
std::shared_ptr<Session> session = nullptr;
SessionID sessionID = 0;
cleanStaleEntries();
auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT;
if (activeSessions < MAX_SESSION_COUNT)
{
do
{
session = std::make_shared<Session>(remoteConsoleSessID, priv);
/*
* Every IPMI Session has two ID's attached to it Remote Console
* Session ID and BMC Session ID. The remote console ID is passed
* along with the Open Session request command. The BMC session ID
* is the key for the session map and is generated using std::rand.
* There is a rare chance for collision of BMC session ID, so the
* following check validates that. In the case of collision the
* created session is reset and a new session is created for
* validating collision.
*/
auto iterator = sessionsMap.find(session->getBMCSessionID());
if (iterator != sessionsMap.end())
{
// Detected BMC Session ID collisions
session.reset();
continue;
}
else
{
break;
}
} while (1);
// Set the Authentication Algorithm
switch (authAlgo)
{
case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
{
session->setAuthAlgo(
std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
cryptAlgo));
break;
}
case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256:
{
session->setAuthAlgo(
std::make_unique<cipher::rakp_auth::AlgoSHA256>(intAlgo,
cryptAlgo));
break;
}
default:
{
throw std::runtime_error("Invalid Authentication Algorithm");
}
}
sessionID = session->getBMCSessionID();
sessionsMap.emplace(sessionID, session);
return session;
}
log<level::INFO>("No free RMCP+ sessions left");
throw std::runtime_error("No free sessions left");
}
bool Manager::stopSession(SessionID bmcSessionID)
{
auto iter = sessionsMap.find(bmcSessionID);
if (iter != sessionsMap.end())
{
iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
return true;
}
else
{
return false;
}
}
std::shared_ptr<Session> Manager::getSession(SessionID sessionID,
RetrieveOption option)
{
switch (option)
{
case RetrieveOption::BMC_SESSION_ID:
{
auto iter = sessionsMap.find(sessionID);
if (iter != sessionsMap.end())
{
return iter->second;
}
break;
}
case RetrieveOption::RC_SESSION_ID:
{
auto iter = std::find_if(
sessionsMap.begin(), sessionsMap.end(),
[sessionID](
const std::pair<const uint32_t, std::shared_ptr<Session>>&
in) -> bool {
return sessionID == in.second->getRCSessionID();
});
if (iter != sessionsMap.end())
{
return iter->second;
}
break;
}
default:
throw std::runtime_error("Invalid retrieval option");
}
throw std::runtime_error("Session ID not found");
}
void Manager::cleanStaleEntries()
{
for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
{
auto session = iter->second;
if ((session->getBMCSessionID() != SESSION_ZERO) &&
!(session->isSessionActive()))
{
iter = sessionsMap.erase(iter);
}
else
{
++iter;
}
}
}
} // namespace session