1 #include "payload_cmds.hpp" 2 3 #include "sessions_manager.hpp" 4 #include "sol/sol_manager.hpp" 5 #include "sol_cmds.hpp" 6 7 #include <ipmid/api.h> 8 9 #include <ipmid/api-types.hpp> 10 #include <phosphor-logging/lg2.hpp> 11 12 namespace sol 13 { 14 15 namespace command 16 { 17 18 std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload, 19 std::shared_ptr<message::Handler>& handler) 20 { 21 auto request = 22 reinterpret_cast<const ActivatePayloadRequest*>(inPayload.data()); 23 if (inPayload.size() != sizeof(*request)) 24 { 25 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 26 return errorPayload; 27 } 28 29 std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse)); 30 auto response = 31 reinterpret_cast<ActivatePayloadResponse*>(outPayload.data()); 32 33 response->completionCode = IPMI_CC_OK; 34 35 // SOL is the payload currently supported for activation. 36 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 37 { 38 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 39 return outPayload; 40 } 41 42 sol::Manager::get().updateSOLParameter(ipmi::convertCurrentChannelNum( 43 ipmi::currentChNum, getInterfaceIndex())); 44 if (!sol::Manager::get().enable) 45 { 46 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 47 return outPayload; 48 } 49 50 // Only one instance of SOL is currently supported. 51 if (request->payloadInstance != 1) 52 { 53 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 54 return outPayload; 55 } 56 57 auto session = session::Manager::get().getSession(handler->sessionID); 58 59 if (!request->encryption && session->isCryptAlgoEnabled()) 60 { 61 response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION; 62 return outPayload; 63 } 64 65 // Is SOL Payload enabled for this user & channel. 66 auto userId = ipmi::ipmiUserGetUserId(session->userName); 67 ipmi::PayloadAccess payloadAccess = {}; 68 if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId, 69 payloadAccess) != IPMI_CC_OK) || 70 !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>( 71 message::PayloadType::SOL)])) 72 { 73 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 74 return outPayload; 75 } 76 77 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 78 if (status) 79 { 80 response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; 81 return outPayload; 82 } 83 84 // Set the current command's socket channel to the session 85 handler->setChannelInSession(); 86 87 // Start the SOL payload 88 try 89 { 90 sol::Manager::get().startPayloadInstance(request->payloadInstance, 91 handler->sessionID); 92 } 93 catch (const std::exception& e) 94 { 95 lg2::error("Failed to start SOL payload: {ERROR}", "ERROR", e); 96 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 97 return outPayload; 98 } 99 100 response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 101 response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 102 response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); 103 104 // VLAN addressing is not used 105 response->vlanNum = 0xFFFF; 106 107 return outPayload; 108 } 109 110 std::vector<uint8_t> 111 deactivatePayload(const std::vector<uint8_t>& inPayload, 112 std::shared_ptr<message::Handler>& /* handler */) 113 { 114 auto request = 115 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 116 if (inPayload.size() != sizeof(*request)) 117 { 118 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 119 return errorPayload; 120 } 121 122 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 123 auto response = 124 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 125 response->completionCode = IPMI_CC_OK; 126 127 // SOL is the payload currently supported for deactivation 128 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 129 { 130 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 131 return outPayload; 132 } 133 134 // Only one instance of SOL is supported 135 if (request->payloadInstance != 1) 136 { 137 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 138 return outPayload; 139 } 140 141 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 142 if (!status) 143 { 144 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 145 return outPayload; 146 } 147 148 try 149 { 150 auto& context = 151 sol::Manager::get().getContext(request->payloadInstance); 152 auto sessionID = context.sessionID; 153 154 sol::Manager::get().stopPayloadInstance(request->payloadInstance); 155 156 try 157 { 158 activating(request->payloadInstance, sessionID); 159 } 160 catch (const std::exception& e) 161 { 162 lg2::info("Failed to call the activating method: {ERROR}", "ERROR", 163 e); 164 /* 165 * In case session has been closed (like in the case of inactivity 166 * timeout), then activating function would throw an exception, 167 * since sessionID is not found. IPMI success completion code is 168 * returned, since the session is closed. 169 */ 170 return outPayload; 171 } 172 } 173 catch (const std::exception& e) 174 { 175 lg2::error("Failed to call the getContext method: {ERROR}", "ERROR", e); 176 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 177 return outPayload; 178 } 179 180 return outPayload; 181 } 182 183 std::vector<uint8_t> 184 getPayloadStatus(const std::vector<uint8_t>& inPayload, 185 std::shared_ptr<message::Handler>& /* handler */) 186 { 187 auto request = 188 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 189 if (inPayload.size() != sizeof(*request)) 190 { 191 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 192 return errorPayload; 193 } 194 195 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 196 auto response = 197 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 198 199 // SOL is the payload currently supported for payload status 200 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 201 { 202 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 203 return outPayload; 204 } 205 206 response->completionCode = IPMI_CC_OK; 207 208 constexpr size_t maxSolPayloadInstances = 1; 209 response->capacity = maxSolPayloadInstances; 210 211 // Currently we support only one SOL session 212 response->instance1 = sol::Manager::get().isPayloadActive(1); 213 214 return outPayload; 215 } 216 217 std::vector<uint8_t> 218 getPayloadInfo(const std::vector<uint8_t>& inPayload, 219 std::shared_ptr<message::Handler>& /* handler */) 220 { 221 auto request = 222 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 223 224 if (inPayload.size() != sizeof(*request)) 225 { 226 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 227 return errorPayload; 228 } 229 230 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 231 auto response = 232 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 233 234 // SOL is the payload currently supported for payload status & only one 235 // instance of SOL is supported. 236 if (static_cast<uint8_t>(message::PayloadType::SOL) != 237 request->payloadType || 238 request->payloadInstance != 1) 239 { 240 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 241 return outPayload; 242 } 243 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 244 245 if (status) 246 { 247 auto& context = 248 sol::Manager::get().getContext(request->payloadInstance); 249 response->sessionID = context.sessionID; 250 } 251 else 252 { 253 // No active payload - return session id as 0 254 response->sessionID = 0; 255 } 256 response->completionCode = IPMI_CC_OK; 257 return outPayload; 258 } 259 260 } // namespace command 261 262 } // namespace sol 263