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