blob: a8e23614cd16166f96069b7e16a51acd03dddd07 [file] [log] [blame]
#include "sessions_manager.hpp"
#include "main.hpp"
#include "session.hpp"
#include <algorithm>
#include <cstdlib>
#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.
*/
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>
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 bmcSessionID = 0;
cleanStaleEntries();
uint8_t sessionHandle = 0;
auto activeSessions = sessionsMap.size() - session::maxSessionlessCount;
if (activeSessions < session::maxSessionCountPerChannel)
{
do
{
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
* 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(bmcSessionID);
if (iterator != sessionsMap.end())
{
// Detected BMC Session ID collisions
continue;
}
else
{
break;
}
} 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)
{
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");
}
}
sessionsMap.emplace(bmcSessionID, session);
session->sessionHandle(sessionHandle);
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(
static_cast<uint8_t>(session::State::tearDownInProgress));
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::sessionZero) &&
!(session->isSessionActive(session->state())))
{
sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0;
iter = sessionsMap.erase(iter);
}
else
{
++iter;
}
}
}
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