From b05fb3231810865ef1b6e627bb0452ae7a6c61f8 Mon Sep 17 00:00:00 2001 From: ssekar Date: Wed, 12 Dec 2018 16:04:15 +0530 Subject: [PATCH 1/2] Adding support for GetSessionInfo command Description: user can get all session info (remote ip,port, session id, priv, etc) using this command. Verification :we can get all active and non active session info by session handle session id. Updated the Remote IP addr and Port update for sessioninfo. Unit testing are done. Change-Id: I662ef2b9f0c1d6bda331eb6481d7b9f34534541b Signed-off-by: ssekar --- comm_module.cpp | 8 +++ command/session_cmds.cpp | 147 +++++++++++++++++++++++++++++++++++++++ command/session_cmds.hpp | 55 +++++++++++++++ message_handler.cpp | 1 + sessions_manager.cpp | 55 +++++++++++++++ sessions_manager.hpp | 7 ++ socket_channel.hpp | 17 +++++ 7 files changed, 290 insertions(+) diff --git a/comm_module.cpp b/comm_module.cpp index acc9089..7a1a17d 100644 --- a/comm_module.cpp +++ b/comm_module.cpp @@ -53,6 +53,14 @@ void sessionSetupCommands() &closeSession, session::Privilege::CALLBACK, false}, + // Session Info Command + { + { + (static_cast(message::PayloadType::IPMI) << 16) | + static_cast(command::NetFns::APP) | 0x3D + }, + &getSessionInfo, session::Privilege::USER, false + }, }; for (auto& iter : commands) diff --git a/command/session_cmds.cpp b/command/session_cmds.cpp index 8606ce5..4beeb6e 100644 --- a/command/session_cmds.cpp +++ b/command/session_cmds.cpp @@ -8,6 +8,14 @@ namespace command { +// Defined as per IPMI sepcification +static constexpr uint8_t searchCurrentSession = 0x00; +static constexpr uint8_t searchSessionByHandle = 0xFE; +static constexpr uint8_t searchSessionByID = 0xFF; + +static constexpr uint8_t ipmi15VerSession = 0x00; +static constexpr uint8_t ipmi20VerSession = 0x01; + std::vector setSessionPrivilegeLevel(const std::vector& inPayload, const message::Handler& handler) @@ -92,4 +100,143 @@ std::vector closeSession(const std::vector& inPayload, return outPayload; } +std::vector getSessionInfo(const std::vector& inPayload, + const message::Handler& handler) + +{ + std::vector outPayload(sizeof(GetSessionInfoResponse)); + auto request = + reinterpret_cast(inPayload.data()); + auto response = + reinterpret_cast(outPayload.data()); + uint32_t reqSessionID = handler.sessionID; + response->completionCode = IPMI_CC_OK; + if (inPayload.size() == 1 && request->sessionIndex != 0) + { + if (request->sessionIndex <= session::MAX_SESSION_COUNT) + { + reqSessionID = std::get(singletonPool) + .getSessionIDbyHandle(request->sessionIndex); + } + else + { + response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + } + + // Here we look for session info according to session index parameter + switch (request->sessionIndex) + { + // Look for current active session which this cmd is received over + case searchCurrentSession: + // Request data should only contain session index byte + if (inPayload.size() != 1) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + // To look for current active session which the command came over, + // the session ID cannot be 0. + if (0 == reqSessionID) + { + response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + break; + case searchSessionByHandle: + // Request data should only contain session index byte and Session + // handle + if (inPayload.size() != 2) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + + // Retrieve session id based on session handle + if (request->sessionHandle <= session::MAX_SESSION_COUNT) + { + reqSessionID = + std::get(singletonPool) + .getSessionIDbyHandle(request->sessionHandle); + } + else + { + response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + break; + case searchSessionByID: + // Request data should only contain session index byte and Session + // handle + if (inPayload.size() != sizeof(GetSessionInfoRequest)) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + reqSessionID = endian::from_ipmi(request->sessionID); + + break; + default: + if (inPayload.size() != 1) + { + response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + } + + response->totalSessionCount = session::MAX_SESSION_COUNT; + response->activeSessioncount = + std::get(singletonPool).getNoOfActiveSession(); + response->sessionHandle = 0; + if (reqSessionID != 0) + { + + std::shared_ptr sessionInfo; + try + { + sessionInfo = std::get(singletonPool) + .getSession(reqSessionID); + } + catch (std::exception& e) + { + response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + response->sessionHandle = std::get(singletonPool) + .getSessionHandle(reqSessionID); + uint8_t userId = ipmi::ipmiUserGetUserId(sessionInfo->userName); + if (userId == ipmi::invalidUserId) + { + response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; + outPayload.resize(sizeof(response->completionCode)); + return std::move(outPayload); + } + response->userID = userId; // userId; + response->privLevel = static_cast(sessionInfo->curPrivLevel); + response->chanNum = sessionInfo->chNum; // byte7 3:0 + response->ipmiVer = ipmi20VerSession; // byte7 7:4 + response->remoteIpAddr = + sessionInfo->channelPtr->getRemoteAddressInbytes(); + response->remotePort = + sessionInfo->channelPtr->getPort(); // remoteSessionPort; + + std::cerr << "\nSessionInfo:" << (int)reqSessionID; + // TODO: Filling the Remote MACAddress + } + else + { + outPayload.resize(4); + } + return std::move(outPayload); +} + } // namespace command diff --git a/command/session_cmds.hpp b/command/session_cmds.hpp index 9737fdb..741de23 100644 --- a/command/session_cmds.hpp +++ b/command/session_cmds.hpp @@ -116,4 +116,59 @@ struct CloseSessionResponse std::vector closeSession(const std::vector& inPayload, const message::Handler& handler); +/** + * @struct GetSessionInfoRequest + * + * IPMI Request data for getSession info command + */ +struct GetSessionInfoRequest +{ + uint8_t sessionIndex; + union + { + uint8_t sessionHandle; + uint32_t sessionID; + }; +} __attribute__((packed)); + +/** + * @struct getSessionInfoResponse + * + * IPMI Response data for getSession info command + */ +struct GetSessionInfoResponse +{ + uint8_t completionCode; + uint8_t sessionHandle; + uint8_t totalSessionCount; + uint8_t activeSessioncount; + uint8_t userID; + uint8_t privLevel; +#if BYTE_ORDER == LITTLE_ENDIAN + uint8_t chanNum : 4; + uint8_t ipmiVer : 4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint8_t ipmiVer : 4; + uint8_t chanNum : 4; +#endif + uint32_t remoteIpAddr; // for channel private data + uint8_t remoteMACAddr[6]; + uint16_t remotePort; +} __attribute__((packed)); + +/** + * @brief GetSessionInfo Command + * + * This command is used to get the session information based on + * session handle or session ID. Retreive all session information. + + * @param[in] inPayload - Request Data for the command + * @param[in] handler - Reference to the Message Handler + * + * @return Response data for the command + */ +std::vector getSessionInfo(const std::vector& inPayload, + const message::Handler& handler); + } // namespace command diff --git a/message_handler.cpp b/message_handler.cpp index e2aafb3..b335236 100644 --- a/message_handler.cpp +++ b/message_handler.cpp @@ -43,6 +43,7 @@ bool Handler::receive() sessionID = inMessage->bmcSessionID; inMessage->rcSessionID = session->getRCSessionID(); session->updateLastTransactionTime(); + session->channelPtr = channel; return true; } diff --git a/sessions_manager.cpp b/sessions_manager.cpp index 95a8a15..9f3210b 100644 --- a/sessions_manager.cpp +++ b/sessions_manager.cpp @@ -88,6 +88,9 @@ std::shared_ptr } sessionID = session->getBMCSessionID(); sessionsMap.emplace(sessionID, session); + storeSessionHandle(sessionID); + + return session; } @@ -149,12 +152,15 @@ std::shared_ptr Manager::getSession(SessionID sessionID, void Manager::cleanStaleEntries() { + uint8_t sessionIndex = 0; for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();) { auto session = iter->second; if ((session->getBMCSessionID() != SESSION_ZERO) && !(session->isSessionActive())) { + sessionIndex = getSessionHandle(session->getBMCSessionID()); + sessionHandleMap[sessionIndex] = 0; iter = sessionsMap.erase(iter); } else @@ -164,4 +170,53 @@ void Manager::cleanStaleEntries() } } +uint8_t Manager::storeSessionHandle(SessionID bmcSessionID) +{ + // Zero handler is reserved for invalid session. + //index starts with 1, for direct usage. Index 0 reserved + for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++) + { + if (sessionHandleMap[i] == 0) + { + sessionHandleMap[i] = bmcSessionID; + break; + } + } + return 0; +} + +uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const +{ + if (sessionHandle <= MAX_SESSION_COUNT) + { + return sessionHandleMap[sessionHandle]; + } + return 0; +} + +uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const +{ + + for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++) + { + if (sessionHandleMap[i] == bmcSessionID) + { + return i; + } + } + return 0; +} +uint8_t Manager::getNoOfActiveSession() const +{ + uint8_t count = 0; + for (const auto& it : sessionsMap) + { + const auto& session = it.second; + if (session->state == State::ACTIVE) + { + count++; + } + } + return count; +} } // namespace session diff --git a/sessions_manager.hpp b/sessions_manager.hpp index 9fd38b1..f6ed1c3 100644 --- a/sessions_manager.hpp +++ b/sessions_manager.hpp @@ -82,8 +82,15 @@ class Manager std::shared_ptr getSession(SessionID sessionID, RetrieveOption option = RetrieveOption::BMC_SESSION_ID); + uint8_t getNoOfActiveSession() const; + uint8_t getSessionHandle(SessionID bmcSessionID) const; + uint8_t storeSessionHandle(SessionID bmcSessionID); + uint32_t getSessionIDbyHandle(uint8_t sessionHandle) const; private: + //+1 for session, as 0 is reserved for sessionless command + std::array sessionHandleMap; + /** * @brief Session Manager keeps the session objects as a sorted * associative container with Session ID as the unique key diff --git a/socket_channel.hpp b/socket_channel.hpp index ebe0c8f..349701e 100644 --- a/socket_channel.hpp +++ b/socket_channel.hpp @@ -64,6 +64,23 @@ class Channel return endpoint.port(); } + /** + * @brief Return the binary representation of the remote IPv4 address + * + * getSessionInfo needs to return the remote IPv4 addresses of each session + * + * @return A uint32_t representation of the remote IPv4 address + */ + std::uint32_t getRemoteAddressInbytes() + { + const boost::asio::ip::address& addr = endpoint.address(); + if (addr.is_v4()) + { + return addr.to_v4().to_uint(); + } + return 0; + } + /** * @brief Read the incoming packet * -- 2.17.1