From f71444da816b23cb27772662a544d8bc1c465273 Mon Sep 17 00:00:00 2001 From: Rajashekar Gade Reddy Date: Thu, 25 Jul 2019 15:12:17 +0000 Subject: Implemented get session info cmd in host interface This command can get info of any session Tested all positive and negative test cases Tested: Get active session info by valid session handle ipmitool raw 0x6 0x3d Response : successfully gets the session info as per IPMI spec Get active session info by valid session id ipmitool raw 0x6 0x3d Response : successfully gets the session info as per IPMI spec Get inactive session info by valid session handle ipmitool raw 0x6 0x3d Response : successfully gets the session info as per IPMI spec Get inactive session info by valid session id ipmitool raw 0x6 0x3d Response : successfully gets the session info as per IPMI spec Get session info by invalid session handle ipmitool raw 0x6 0x3d Response : 0x88 // Inavlid Session Handle Get session info by invalid session id ipmitool raw 0x6 0x3d Response : 0x87 // Inavlid Session Id Signed-off-by: Rajashekar Gade Reddy Change-Id: Ib36a9fe5eac58d15011cc9379ceed480ba0be96d --- apphandler.cpp | 275 +++++++++++++++++++++++++++++++++++++++++++ include/ipmid/sessiondef.hpp | 3 +- 2 files changed, 277 insertions(+), 1 deletion(-) diff --git a/apphandler.cpp b/apphandler.cpp index f187d95..03cd255 100644 --- a/apphandler.cpp +++ b/apphandler.cpp @@ -949,6 +949,277 @@ ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId, return ipmi::responseInvalidFieldRequest(); } +uint8_t getTotalSessionCount() +{ + uint8_t count = 0, ch = 1; + + while (ch < ipmi::maxIpmiChannels && + count < session::maxNetworkInstanceSupported) + { + ipmi::ChannelInfo chInfo; + ipmi::getChannelInfo(ch, chInfo); + if (static_cast(chInfo.mediumType) == + ipmi::EChannelMediumType::lan8032) + { + count++; + } + ch++; + } + return count * session::maxSessionCountPerChannel; +} + +/** + * @brief get session info request data. + * + * This function validates the request data and retrive request session id, + * session handle. + * + * @param[in] sessionIndex - request session index + * @param[in] payload - input payload + * @param[in] reqSessionId - unpacked session Id will be asigned + * @param[in] reqSessionHandle - unpacked session handle will be asigned + * + * @return success completion code if request data is valid + * else return the correcponding error completion code. + **/ +uint8_t getSessionInfoRequestData(const uint8_t sessionIndex, + ipmi::message::Payload& payload, + uint32_t& reqSessionId, + uint8_t& reqSessionHandle) +{ + if (sessionIndex == session::sessionZero || + ((sessionIndex > session::maxSessionCountPerChannel) && + (sessionIndex < session::searchSessionByHandle))) + { + return ipmi::ccInvalidFieldRequest; + } + + switch (sessionIndex) + { + case session::searchSessionByHandle: + + if ((payload.unpack(reqSessionHandle)) || + (!payload.fullyUnpacked())) + { + return ipmi::ccReqDataLenInvalid; + } + + if ((reqSessionHandle == session::sessionZero) || + ((reqSessionHandle & session::multiIntfaceSessionHandleMask) > + session::maxSessionCountPerChannel)) + { + return session::ccInvalidSessionHandle; + } + break; + + case session::searchSessionById: + + if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked())) + { + return ipmi::ccReqDataLenInvalid; + } + + if (reqSessionId == session::sessionZero) + { + return session::ccInvalidSessionId; + } + break; + + default: + if (!payload.fullyUnpacked()) + { + return ipmi::ccReqDataLenInvalid; + } + break; + } + return ipmi::ccSuccess; +} + +uint8_t getSessionState(std::shared_ptr& busp, + const std::string& service, const std::string& objPath, + uint8_t& sessionState) +{ + try + { + sessionState = std::get(ipmi::getDbusProperty( + *busp, service, objPath, session::sessionIntf, "State")); + } + catch (sdbusplus::exception::SdBusError& e) + { + log("Failed to fetch state property ", + entry("SERVICE=%s", service.c_str()), + entry("OBJECTPATH=%s", objPath.c_str()), + entry("INTERFACE=%s", session::sessionIntf), + entry("ERRMSG=%s", e.what())); + return ipmi::ccUnspecifiedError; + } + + return ipmi::ccSuccess; +} + +static constexpr uint8_t macAddrLen = 6; +struct GetSessionInfoRes +{ + uint8_t sessionHandle; + uint8_t totalSessionCount; + uint8_t activeSessionCount; + uint8_t userID; + uint8_t privLevel; + uint8_t channelNumber; + uint32_t remoteIpAddr; + std::array macAddr = {0}; + uint16_t remotePort; +}; + +uint8_t + fillGetSessionInfoRes(std::shared_ptr& busp, + const std::string& service, + const std::string& objPath, + struct GetSessionInfoRes& resp, uint8_t& sessionState) +{ + try + { + ipmi::PropertyMap sessionProps = ipmi::getAllDbusProperties( + *busp, service, objPath, session::sessionIntf); + + sessionState = std::get(sessionProps.at("State")); + if (sessionState == static_cast(session::State::active)) + { + resp.sessionHandle = + std::get(sessionProps["SessionHandle"]); + resp.userID = std::get(sessionProps["UserID"]); + resp.privLevel = + std::get(sessionProps["CurrentPrivilege"]); + resp.channelNumber = std::get(sessionProps["ChannelNum"]); + resp.remoteIpAddr = + std::get(sessionProps["RemoteIPAddr"]); + resp.remotePort = std::get(sessionProps["RemotePort"]); + } + } + catch (sdbusplus::exception::SdBusError& e) + { + log("Failed to fetch state property ", + entry("SERVICE=%s", service.c_str()), + entry("OBJECTPATH=%s", objPath.c_str()), + entry("INTERFACE=%s", session::sessionIntf), + entry("ERRMSG=%s", e.what())); + return ipmi::ccUnspecifiedError; + } + + return ipmi::ccSuccess; +} + +ipmi::RspType< + uint8_t, // session handle, + uint8_t, // total session count + uint8_t, // active session count + std::optional, // mac address + uint16_t // remote port + >>> + ipmiAppGetSessionInfo(uint8_t sessionIndex, ipmi::message::Payload& payload) +{ + uint32_t reqSessionId = 0; + uint8_t reqSessionHandle = session::defaultSessionHandle; + // initializing state to 0xff as 0 represents state as inactive. + uint8_t state = 0xFF; + + uint8_t completionCode = getSessionInfoRequestData( + sessionIndex, payload, reqSessionId, reqSessionHandle); + + if (completionCode) + { + return ipmi::response(completionCode); + } + struct GetSessionInfoRes res = {0}; + res.totalSessionCount = getTotalSessionCount(); + res.activeSessionCount = 0; + auto busp = getSdBus(); + + try + { + uint8_t index = 0; + ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects( + *busp, session::sessionManagerRootPath, session::sessionIntf); + + for (auto& objectTreeItr : objectTree) + { + uint32_t sessionId = 0; + uint8_t sessionHandle = session::defaultSessionHandle; + std::string objectPath = objectTreeItr.first; + + if (!parseCloseSessionInputPayload(objectPath, sessionId, + sessionHandle)) + { + continue; + } + index++; + auto& serviceMap = objectTreeItr.second; + auto itr = serviceMap.begin(); + + if (serviceMap.size() != 1) + { + return ipmi::responseUnspecifiedError(); + } + + std::string service = itr->first; + uint8_t sessionState = 0; + completionCode = + getSessionState(busp, service, objectPath, sessionState); + if (completionCode) + { + return ipmi::response(completionCode); + } + + if (sessionState == static_cast(session::State::active)) + { + res.activeSessionCount++; + } + + if (index != sessionIndex && reqSessionId != sessionId && + reqSessionHandle != sessionHandle) + { + continue; + } + + completionCode = + fillGetSessionInfoRes(busp, service, objectPath, res, state); + + if (completionCode) + { + return ipmi::response(completionCode); + } + } + } + + catch (sdbusplus::exception::SdBusError& e) + { + log("Failed to fetch object from dbus", + entry("INTERFACE=%s", session::sessionIntf), + entry("ERRMSG=%s", e.what())); + return ipmi::responseUnspecifiedError(); + } + + if (state == static_cast(session::State::active)) + { + return ipmi::responseSuccess( + res.sessionHandle, res.totalSessionCount, res.activeSessionCount, + std::make_tuple(res.userID, res.privLevel, res.channelNumber, + res.remoteIpAddr, res.macAddr, res.remotePort)); + } + else if (state == static_cast(session::State::tearDownInProgress)) + { + res.sessionHandle = 0; + return ipmi::responseSuccess(res.sessionHandle, res.totalSessionCount, + res.activeSessionCount, std::nullopt); + } + + return ipmi::responseInvalidFieldRequest(); +} + static std::unique_ptr sysInfoParamStore; static std::string sysInfoReadSystemName() @@ -1366,6 +1637,10 @@ void register_netfn_app_functions() ipmi::app::cmdResetWatchdogTimer, ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer); + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, + ipmi::app::cmdGetSessionInfo, + ipmi::Privilege::Callback, ipmiAppGetSessionInfo); + // ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, ipmi::app::cmdSetWatchdogTimer, diff --git a/include/ipmid/sessiondef.hpp b/include/ipmid/sessiondef.hpp index 48ee4c6..7802fb9 100644 --- a/include/ipmid/sessiondef.hpp +++ b/include/ipmid/sessiondef.hpp @@ -32,7 +32,8 @@ static constexpr uint8_t defaultSessionHandle = 0xFF; static constexpr uint8_t maxNetworkInstanceSupported = 4; static constexpr uint8_t ccInvalidSessionId = 0x87; static constexpr uint8_t ccInvalidSessionHandle = 0x88; - +static constexpr uint8_t searchSessionByHandle = 0xFE; +static constexpr uint8_t searchSessionById = 0xFF; // MSB BIT 7 BIT 6 assigned for netipmid instance in session handle. static constexpr uint8_t multiIntfaceSessionHandleMask = 0x3F; -- cgit v1.2.1