#include "payload_cmds.hpp" #include "sessions_manager.hpp" #include "sol/sol_manager.hpp" #include "sol_cmds.hpp" #include #include #include namespace sol { namespace command { std::vector activatePayload(const std::vector& inPayload, std::shared_ptr& handler) { auto request = reinterpret_cast(inPayload.data()); if (inPayload.size() != sizeof(*request)) { std::vector errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; return errorPayload; } std::vector outPayload(sizeof(ActivatePayloadResponse)); auto response = reinterpret_cast(outPayload.data()); response->completionCode = IPMI_CC_OK; // SOL is the payload currently supported for activation. if (static_cast(message::PayloadType::SOL) != request->payloadType) { response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; return outPayload; } sol::Manager::get().updateSOLParameter(ipmi::convertCurrentChannelNum( ipmi::currentChNum, getInterfaceIndex())); if (!sol::Manager::get().enable) { response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; return outPayload; } // Only one instance of SOL is currently supported. if (request->payloadInstance != 1) { response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; return outPayload; } auto session = session::Manager::get().getSession(handler->sessionID); if (!request->encryption && session->isCryptAlgoEnabled()) { response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION; return outPayload; } if (session->currentPrivilege() < static_cast(sol::Manager::get().solMinPrivilege)) { response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; return outPayload; } // Is SOL Payload enabled for this user & channel. auto userId = ipmi::ipmiUserGetUserId(session->userName); ipmi::PayloadAccess payloadAccess = {}; if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId, payloadAccess) != IPMI_CC_OK) || !(payloadAccess.stdPayloadEnables1[static_cast( message::PayloadType::SOL)])) { response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; return outPayload; } auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); if (status) { response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; return outPayload; } // Set the current command's socket channel to the session handler->setChannelInSession(); // Start the SOL payload try { sol::Manager::get().startPayloadInstance(request->payloadInstance, handler->sessionID); } catch (const std::exception& e) { lg2::error("Failed to start SOL payload: {ERROR}", "ERROR", e); response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; return outPayload; } response->inPayloadSize = endian::to_ipmi(MAX_PAYLOAD_SIZE); response->outPayloadSize = endian::to_ipmi(MAX_PAYLOAD_SIZE); response->portNum = endian::to_ipmi(IPMI_STD_PORT); // VLAN addressing is not used response->vlanNum = 0xFFFF; return outPayload; } std::vector deactivatePayload(const std::vector& inPayload, std::shared_ptr& handler) { auto request = reinterpret_cast(inPayload.data()); if (inPayload.size() != sizeof(*request)) { std::vector errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; return errorPayload; } std::vector outPayload(sizeof(DeactivatePayloadResponse)); auto response = reinterpret_cast(outPayload.data()); response->completionCode = IPMI_CC_OK; // SOL is the payload currently supported for deactivation if (static_cast(message::PayloadType::SOL) != request->payloadType) { response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; return outPayload; } // Only one instance of SOL is supported if (request->payloadInstance != 1) { response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; return outPayload; } auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); if (!status) { response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; return outPayload; } auto currentSession = session::Manager::get().getSession(handler->sessionID); auto solSessionID = sol::Manager::get().getContext(request->payloadInstance).sessionID; auto solActiveSession = sol::Manager::get().getContext(request->payloadInstance).session; // The session owner or the ADMIN could deactivate the session if (currentSession->userName != solActiveSession->userName && currentSession->currentPrivilege() != static_cast(session::Privilege::ADMIN)) { response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; return outPayload; } try { sol::Manager::get().stopPayloadInstance(request->payloadInstance); try { activating(request->payloadInstance, solSessionID); } catch (const std::exception& e) { lg2::info("Failed to call the activating method: {ERROR}", "ERROR", e); /* * In case session has been closed (like in the case of inactivity * timeout), then activating function would throw an exception, * since solSessionID is not found. As session is already closed, * returning IPMI status code for Payload already deactivated * as BMC automatically deactivates all active payloads when * session is terminated. */ response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; return outPayload; } } catch (const std::exception& e) { lg2::error("Failed to call the getContext method: {ERROR}", "ERROR", e); response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; return outPayload; } return outPayload; } std::vector getPayloadStatus(const std::vector& inPayload, std::shared_ptr& /* handler */) { auto request = reinterpret_cast(inPayload.data()); if (inPayload.size() != sizeof(*request)) { std::vector errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; return errorPayload; } std::vector outPayload(sizeof(GetPayloadStatusResponse)); auto response = reinterpret_cast(outPayload.data()); // SOL is the payload currently supported for payload status if (static_cast(message::PayloadType::SOL) != request->payloadType) { response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; return outPayload; } response->completionCode = IPMI_CC_OK; constexpr size_t maxSolPayloadInstances = 1; response->capacity = maxSolPayloadInstances; // Currently we support only one SOL session response->instance1 = sol::Manager::get().isPayloadActive(1); return outPayload; } std::vector getPayloadInfo(const std::vector& inPayload, std::shared_ptr& /* handler */) { auto request = reinterpret_cast(inPayload.data()); if (inPayload.size() != sizeof(*request)) { std::vector errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; return errorPayload; } std::vector outPayload(sizeof(GetPayloadInfoResponse)); auto response = reinterpret_cast(outPayload.data()); // SOL is the payload currently supported for payload status & only one // instance of SOL is supported. if (static_cast(message::PayloadType::SOL) != request->payloadType || request->payloadInstance != 1) { response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; return outPayload; } auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); if (status) { auto& context = sol::Manager::get().getContext(request->payloadInstance); response->sessionID = context.sessionID; } else { // No active payload - return session id as 0 response->sessionID = 0; } response->completionCode = IPMI_CC_OK; return outPayload; } } // namespace command } // namespace sol