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 if (session->currentPrivilege() < 66 static_cast<uint8_t>(sol::Manager::get().solMinPrivilege)) 67 { 68 response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; 69 return outPayload; 70 } 71 72 // Is SOL Payload enabled for this user & channel. 73 auto userId = ipmi::ipmiUserGetUserId(session->userName); 74 ipmi::PayloadAccess payloadAccess = {}; 75 if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId, 76 payloadAccess) != IPMI_CC_OK) || 77 !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>( 78 message::PayloadType::SOL)])) 79 { 80 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 81 return outPayload; 82 } 83 84 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 85 if (status) 86 { 87 response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; 88 return outPayload; 89 } 90 91 // Set the current command's socket channel to the session 92 handler->setChannelInSession(); 93 94 // Start the SOL payload 95 try 96 { 97 sol::Manager::get().startPayloadInstance(request->payloadInstance, 98 handler->sessionID); 99 } 100 catch (const std::exception& e) 101 { 102 lg2::error("Failed to start SOL payload: {ERROR}", "ERROR", e); 103 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 104 return outPayload; 105 } 106 107 response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 108 response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 109 response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); 110 111 // VLAN addressing is not used 112 response->vlanNum = 0xFFFF; 113 114 return outPayload; 115 } 116 117 std::vector<uint8_t> 118 deactivatePayload(const std::vector<uint8_t>& inPayload, 119 std::shared_ptr<message::Handler>& handler) 120 { 121 auto request = 122 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 123 if (inPayload.size() != sizeof(*request)) 124 { 125 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 126 return errorPayload; 127 } 128 129 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 130 auto response = 131 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 132 response->completionCode = IPMI_CC_OK; 133 134 // SOL is the payload currently supported for deactivation 135 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 136 { 137 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 138 return outPayload; 139 } 140 141 // Only one instance of SOL is supported 142 if (request->payloadInstance != 1) 143 { 144 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 145 return outPayload; 146 } 147 148 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 149 if (!status) 150 { 151 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 152 return outPayload; 153 } 154 155 auto currentSession = 156 session::Manager::get().getSession(handler->sessionID); 157 auto solSessionID = 158 sol::Manager::get().getContext(request->payloadInstance).sessionID; 159 auto solActiveSession = session::Manager::get().getSession(solSessionID); 160 // The session owner or the ADMIN could deactivate the session 161 if (currentSession->userName != solActiveSession->userName && 162 currentSession->currentPrivilege() != 163 static_cast<uint8_t>(session::Privilege::ADMIN)) 164 { 165 response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; 166 return outPayload; 167 } 168 169 try 170 { 171 sol::Manager::get().stopPayloadInstance(request->payloadInstance); 172 173 try 174 { 175 activating(request->payloadInstance, solSessionID); 176 } 177 catch (const std::exception& e) 178 { 179 lg2::info("Failed to call the activating method: {ERROR}", "ERROR", 180 e); 181 /* 182 * In case session has been closed (like in the case of inactivity 183 * timeout), then activating function would throw an exception, 184 * since solSessionID is not found. IPMI success completion code is 185 * returned, since the session is closed. 186 */ 187 return outPayload; 188 } 189 } 190 catch (const std::exception& e) 191 { 192 lg2::error("Failed to call the getContext method: {ERROR}", "ERROR", e); 193 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 194 return outPayload; 195 } 196 197 return outPayload; 198 } 199 200 std::vector<uint8_t> 201 getPayloadStatus(const std::vector<uint8_t>& inPayload, 202 std::shared_ptr<message::Handler>& /* handler */) 203 { 204 auto request = 205 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 206 if (inPayload.size() != sizeof(*request)) 207 { 208 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 209 return errorPayload; 210 } 211 212 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 213 auto response = 214 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 215 216 // SOL is the payload currently supported for payload status 217 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 218 { 219 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 220 return outPayload; 221 } 222 223 response->completionCode = IPMI_CC_OK; 224 225 constexpr size_t maxSolPayloadInstances = 1; 226 response->capacity = maxSolPayloadInstances; 227 228 // Currently we support only one SOL session 229 response->instance1 = sol::Manager::get().isPayloadActive(1); 230 231 return outPayload; 232 } 233 234 std::vector<uint8_t> 235 getPayloadInfo(const std::vector<uint8_t>& inPayload, 236 std::shared_ptr<message::Handler>& /* handler */) 237 { 238 auto request = 239 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 240 241 if (inPayload.size() != sizeof(*request)) 242 { 243 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 244 return errorPayload; 245 } 246 247 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 248 auto response = 249 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 250 251 // SOL is the payload currently supported for payload status & only one 252 // instance of SOL is supported. 253 if (static_cast<uint8_t>(message::PayloadType::SOL) != 254 request->payloadType || 255 request->payloadInstance != 1) 256 { 257 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 258 return outPayload; 259 } 260 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 261 262 if (status) 263 { 264 auto& context = 265 sol::Manager::get().getContext(request->payloadInstance); 266 response->sessionID = context.sessionID; 267 } 268 else 269 { 270 // No active payload - return session id as 0 271 response->sessionID = 0; 272 } 273 response->completionCode = IPMI_CC_OK; 274 return outPayload; 275 } 276 277 } // namespace command 278 279 } // namespace sol 280