blob: a8e23614cd16166f96069b7e16a51acd03dddd07 [file] [log] [blame]
Tom Joseph3e61aa02016-08-08 08:42:39 -05001#include "sessions_manager.hpp"
2
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +05303#include "main.hpp"
Vernon Mauery9e801a22018-10-12 13:20:49 -07004#include "session.hpp"
5
Tom Joseph3e61aa02016-08-08 08:42:39 -05006#include <algorithm>
7#include <cstdlib>
8#include <iomanip>
Tom Joseph3e61aa02016-08-08 08:42:39 -05009#include <memory>
Vernon Maueryfc37e592018-12-19 14:55:15 -080010#include <phosphor-logging/log.hpp>
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053011#include <sdbusplus/asio/connection.hpp>
12#include <user_channel/channel_layer.hpp>
Vernon Maueryfc37e592018-12-19 14:55:15 -080013
14using namespace phosphor::logging;
Tom Joseph3e61aa02016-08-08 08:42:39 -050015
Tom Joseph3e61aa02016-08-08 08:42:39 -050016namespace session
17{
18
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053019static std::array<uint8_t, session::maxNetworkInstanceSupported>
20 ipmiNetworkChannelNumList = {0};
21
22void Manager::setNetworkInstance(void)
23{
24
25 uint8_t index = 0, ch = 1;
26 // Constructing net-ipmid instances list based on channel info
27 // valid channel start from 1 to 15 and assuming max 4 LAN channel
28 // supported
29
30 while (ch < ipmi::maxIpmiChannels &&
31 index < session::maxNetworkInstanceSupported)
32 {
33 ipmi::ChannelInfo chInfo;
34 ipmi::getChannelInfo(ch, chInfo);
35 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
36 ipmi::EChannelMediumType::lan8032)
37 {
38
39 if (getInterfaceIndex() == ch)
40 {
41 ipmiNetworkInstance = index;
42 }
43
44 ipmiNetworkChannelNumList[index] = ch;
45 index++;
46 }
47 ch++;
48 }
49}
50
51uint8_t Manager::getNetworkInstance(void)
52{
53 return ipmiNetworkInstance;
54}
55
Tom Joseph3e61aa02016-08-08 08:42:39 -050056Manager::Manager()
57{
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053058}
59
60void Manager::managerInit(const std::string& channel)
61{
62
Tom Joseph3e61aa02016-08-08 08:42:39 -050063 /*
64 * Session ID is 0000_0000h for messages that are sent outside the session.
65 * The session setup commands are sent on this session, so when the session
66 * manager comes up, is creates the Session ID 0000_0000h. It is active
67 * through the lifetime of the Session Manager.
68 */
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053069
70 objManager = std::make_unique<sdbusplus::server::manager::manager>(
71 *getSdBus(), session::sessionManagerRootPath);
72
73 auto objPath =
74 std::string(session::sessionManagerRootPath) + "/" + channel + "/0";
75
76 chName = channel;
77 setNetworkInstance();
78 sessionsMap.emplace(
79 0, std::make_shared<Session>(*getSdBus(), objPath.c_str(), 0, 0, 0));
Tom Joseph3e61aa02016-08-08 08:42:39 -050080}
81
Vernon Maueryae1fda42018-10-15 12:55:34 -070082std::shared_ptr<Session>
Vernon Mauery9e801a22018-10-12 13:20:49 -070083 Manager::startSession(SessionID remoteConsoleSessID, Privilege priv,
84 cipher::rakp_auth::Algorithms authAlgo,
85 cipher::integrity::Algorithms intAlgo,
86 cipher::crypt::Algorithms cryptAlgo)
Tom Joseph3e61aa02016-08-08 08:42:39 -050087{
88 std::shared_ptr<Session> session = nullptr;
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053089 SessionID bmcSessionID = 0;
Tom Joseph3e61aa02016-08-08 08:42:39 -050090 cleanStaleEntries();
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053091 uint8_t sessionHandle = 0;
Tom Joseph3e61aa02016-08-08 08:42:39 -050092
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053093 auto activeSessions = sessionsMap.size() - session::maxSessionlessCount;
94
95 if (activeSessions < session::maxSessionCountPerChannel)
Tom Joseph3e61aa02016-08-08 08:42:39 -050096 {
97 do
98 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053099 bmcSessionID = (crypto::prng::rand());
100 bmcSessionID &= session::multiIntfaceSessionIDMask;
101 // In sessionID , BIT 31 BIT30 are used for netipmid instance
102 bmcSessionID |= ipmiNetworkInstance << 30;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500103 /*
104 * Every IPMI Session has two ID's attached to it Remote Console
105 * Session ID and BMC Session ID. The remote console ID is passed
106 * along with the Open Session request command. The BMC session ID
107 * is the key for the session map and is generated using std::rand.
108 * There is a rare chance for collision of BMC session ID, so the
109 * following check validates that. In the case of collision the
Gunnar Mills62ec6222018-04-08 16:28:23 -0500110 * created session is reset and a new session is created for
Tom Joseph3e61aa02016-08-08 08:42:39 -0500111 * validating collision.
112 */
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530113 auto iterator = sessionsMap.find(bmcSessionID);
Tom Joseph3e61aa02016-08-08 08:42:39 -0500114 if (iterator != sessionsMap.end())
115 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700116 // Detected BMC Session ID collisions
Tom Joseph3e61aa02016-08-08 08:42:39 -0500117 continue;
118 }
119 else
120 {
121 break;
122 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700123 } while (1);
Tom Joseph3e61aa02016-08-08 08:42:39 -0500124
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530125 sessionHandle = storeSessionHandle(bmcSessionID);
126
127 if (!sessionHandle)
128 {
129 throw std::runtime_error(
130 "Invalid sessionHandle - No sessionID slot ");
131 }
132 sessionHandle &= session::multiIntfaceSessionHandleMask;
133 // In sessionID , BIT 31 BIT30 are used for netipmid instance
134 sessionHandle |= ipmiNetworkInstance << 6;
135 std::stringstream sstream;
136 sstream << std::hex << bmcSessionID;
137 std::stringstream shstream;
138 shstream << std::hex << (int)sessionHandle;
139 auto objPath = std::string(session::sessionManagerRootPath) + "/" +
140 chName + "/" + sstream.str() + "_" + shstream.str();
141 session = std::make_shared<Session>(*getSdBus(), objPath.c_str(),
142 remoteConsoleSessID, bmcSessionID,
143 static_cast<uint8_t>(priv));
144
Vernon Mauery9b307be2017-11-22 09:28:16 -0800145 // Set the Authentication Algorithm
Tom Joseph3e61aa02016-08-08 08:42:39 -0500146 switch (authAlgo)
147 {
148 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
149 {
150 session->setAuthAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700151 std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
152 cryptAlgo));
Tom Joseph3e61aa02016-08-08 08:42:39 -0500153 break;
154 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800155 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256:
156 {
157 session->setAuthAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700158 std::make_unique<cipher::rakp_auth::AlgoSHA256>(intAlgo,
159 cryptAlgo));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800160 break;
161 }
Tom Joseph3e61aa02016-08-08 08:42:39 -0500162 default:
163 {
164 throw std::runtime_error("Invalid Authentication Algorithm");
165 }
166 }
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530167
168 sessionsMap.emplace(bmcSessionID, session);
169 session->sessionHandle(sessionHandle);
170
Vernon Mauery4cb73592018-10-26 10:15:03 -0700171 return session;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500172 }
Vernon Mauery4cb73592018-10-26 10:15:03 -0700173
Vernon Maueryfc37e592018-12-19 14:55:15 -0800174 log<level::INFO>("No free RMCP+ sessions left");
Vernon Mauery4cb73592018-10-26 10:15:03 -0700175
Vernon Mauery4cb73592018-10-26 10:15:03 -0700176 throw std::runtime_error("No free sessions left");
Tom Joseph3e61aa02016-08-08 08:42:39 -0500177}
178
Tom Joseph9662c3a2016-12-06 17:52:16 +0530179bool Manager::stopSession(SessionID bmcSessionID)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500180{
Tom Joseph9662c3a2016-12-06 17:52:16 +0530181 auto iter = sessionsMap.find(bmcSessionID);
182 if (iter != sessionsMap.end())
Tom Joseph3e61aa02016-08-08 08:42:39 -0500183 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530184 iter->second->state(
185 static_cast<uint8_t>(session::State::tearDownInProgress));
Tom Joseph9662c3a2016-12-06 17:52:16 +0530186 return true;
187 }
188 else
189 {
190 return false;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500191 }
192}
193
Vernon Maueryae1fda42018-10-15 12:55:34 -0700194std::shared_ptr<Session> Manager::getSession(SessionID sessionID,
195 RetrieveOption option)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500196{
197 switch (option)
198 {
199 case RetrieveOption::BMC_SESSION_ID:
200 {
201 auto iter = sessionsMap.find(sessionID);
202 if (iter != sessionsMap.end())
203 {
204 return iter->second;
205 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530206 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500207 }
208 case RetrieveOption::RC_SESSION_ID:
209 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700210 auto iter = std::find_if(
211 sessionsMap.begin(), sessionsMap.end(),
212 [sessionID](
213 const std::pair<const uint32_t, std::shared_ptr<Session>>&
214 in) -> bool {
215 return sessionID == in.second->getRCSessionID();
216 });
Tom Joseph3e61aa02016-08-08 08:42:39 -0500217
218 if (iter != sessionsMap.end())
219 {
220 return iter->second;
221 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530222 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500223 }
224 default:
225 throw std::runtime_error("Invalid retrieval option");
226 }
227
228 throw std::runtime_error("Session ID not found");
229}
230
231void Manager::cleanStaleEntries()
232{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700233 for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500234 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530235
Tom Joseph3e61aa02016-08-08 08:42:39 -0500236 auto session = iter->second;
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530237 if ((session->getBMCSessionID() != session::sessionZero) &&
238 !(session->isSessionActive(session->state())))
Tom Joseph3e61aa02016-08-08 08:42:39 -0500239 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530240 sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500241 iter = sessionsMap.erase(iter);
242 }
243 else
244 {
245 ++iter;
246 }
247 }
248}
249
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530250uint8_t Manager::storeSessionHandle(SessionID bmcSessionID)
251{
252 // Handler index 0 is reserved for invalid session.
253 // index starts with 1, for direct usage. Index 0 reserved
254 for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++)
255 {
256 if (sessionHandleMap[i] == 0)
257 {
258 sessionHandleMap[i] = bmcSessionID;
259 return i;
260 }
261 }
262 return 0;
263}
264
265uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const
266{
267 if (sessionHandle <= session::maxSessionCountPerChannel)
268 {
269 return sessionHandleMap[sessionHandle];
270 }
271 return 0;
272}
273
274uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const
275{
276
277 // Handler index 0 is reserved for invalid session.
278 // index starts with 1, for direct usage. Index 0 reserved
279
280 for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++)
281 {
282 if (sessionHandleMap[i] == bmcSessionID)
283 {
284 return (i);
285 }
286 }
287 return 0;
288}
289uint8_t Manager::getActiveSessionCount() const
290{
291
292 return (std::count_if(
293 sessionsMap.begin(), sessionsMap.end(),
294 [](const std::pair<const uint32_t, std::shared_ptr<Session>>& in)
295 -> bool {
296 return in.second->state() ==
297 static_cast<uint8_t>(session::State::active);
298 }));
299}
Tom Joseph3e61aa02016-08-08 08:42:39 -0500300} // namespace session