1 #include "payload_cmds.hpp" 2 3 #include "main.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 const message::Handler& handler) 22 { 23 std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse)); 24 auto request = 25 reinterpret_cast<const ActivatePayloadRequest*>(inPayload.data()); 26 auto response = 27 reinterpret_cast<ActivatePayloadResponse*>(outPayload.data()); 28 29 if (inPayload.size() != sizeof(ActivatePayloadRequest)) 30 { 31 response->completionCode = ipmi::ccReqDataLenInvalid; 32 outPayload.resize(sizeof(response->completionCode)); 33 return outPayload; 34 } 35 36 response->completionCode = IPMI_CC_OK; 37 38 // SOL is the payload currently supported for activation. 39 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 40 { 41 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 42 return outPayload; 43 } 44 45 if (!std::get<sol::Manager&>(singletonPool).enable) 46 { 47 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 48 return outPayload; 49 } 50 51 // Only one instance of SOL is currently supported. 52 if (request->payloadInstance != 1) 53 { 54 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 55 return outPayload; 56 } 57 58 auto session = std::get<session::Manager&>(singletonPool) 59 .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 = std::get<sol::Manager&>(singletonPool) 80 .isPayloadActive(request->payloadInstance); 81 if (status) 82 { 83 response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; 84 return outPayload; 85 } 86 87 // Set the current command's socket channel to the session 88 handler.setChannelInSession(); 89 90 // Start the SOL payload 91 try 92 { 93 std::get<sol::Manager&>(singletonPool) 94 .startPayloadInstance(request->payloadInstance, handler.sessionID); 95 } 96 catch (std::exception& e) 97 { 98 log<level::ERR>(e.what()); 99 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 100 return outPayload; 101 } 102 103 response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 104 response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 105 response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); 106 107 // VLAN addressing is not used 108 response->vlanNum = 0xFFFF; 109 110 return outPayload; 111 } 112 113 std::vector<uint8_t> deactivatePayload(const std::vector<uint8_t>& inPayload, 114 const message::Handler& handler) 115 { 116 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 117 auto request = 118 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 119 auto response = 120 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 121 122 response->completionCode = IPMI_CC_OK; 123 124 if (inPayload.size() != sizeof(DeactivatePayloadRequest)) 125 { 126 response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; 127 return outPayload; 128 } 129 130 // SOL is the payload currently supported for deactivation 131 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 132 { 133 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 134 return outPayload; 135 } 136 137 // Only one instance of SOL is supported 138 if (request->payloadInstance != 1) 139 { 140 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 141 return outPayload; 142 } 143 144 auto status = std::get<sol::Manager&>(singletonPool) 145 .isPayloadActive(request->payloadInstance); 146 if (!status) 147 { 148 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 149 return outPayload; 150 } 151 152 try 153 { 154 auto& context = std::get<sol::Manager&>(singletonPool) 155 .getContext(request->payloadInstance); 156 auto sessionID = context.sessionID; 157 158 std::get<sol::Manager&>(singletonPool) 159 .stopPayloadInstance(request->payloadInstance); 160 161 try 162 { 163 activating(request->payloadInstance, sessionID); 164 } 165 catch (std::exception& e) 166 { 167 log<level::INFO>(e.what()); 168 /* 169 * In case session has been closed (like in the case of inactivity 170 * timeout), then activating function would throw an exception, 171 * since sessionID is not found. IPMI success completion code is 172 * returned, since the session is closed. 173 */ 174 return outPayload; 175 } 176 177 auto check = 178 std::get<session::Manager&>(singletonPool).stopSession(sessionID); 179 if (!check) 180 { 181 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 182 } 183 } 184 catch (std::exception& e) 185 { 186 log<level::ERR>(e.what()); 187 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 188 return outPayload; 189 } 190 191 return outPayload; 192 } 193 194 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload, 195 const message::Handler& handler) 196 { 197 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 198 auto request = 199 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 200 auto response = 201 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 202 203 // SOL is the payload currently supported for payload status 204 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 205 { 206 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 207 return outPayload; 208 } 209 210 response->completionCode = IPMI_CC_OK; 211 212 constexpr size_t maxSolPayloadInstances = 1; 213 response->capacity = maxSolPayloadInstances; 214 215 // Currently we support only one SOL session 216 response->instance1 = 217 std::get<sol::Manager&>(singletonPool).isPayloadActive(1); 218 219 return outPayload; 220 } 221 222 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload, 223 const message::Handler& handler) 224 { 225 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 226 auto request = 227 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 228 auto response = 229 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 230 231 if (inPayload.size() != sizeof(GetPayloadInfoRequest)) 232 { 233 response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; 234 return outPayload; 235 } 236 // SOL is the payload currently supported for payload status & only one 237 // instance of SOL is supported. 238 if (static_cast<uint8_t>(message::PayloadType::SOL) != 239 request->payloadType || 240 request->payloadInstance != 1) 241 { 242 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 243 return outPayload; 244 } 245 auto status = std::get<sol::Manager&>(singletonPool) 246 .isPayloadActive(request->payloadInstance); 247 248 if (status) 249 { 250 auto& context = std::get<sol::Manager&>(singletonPool) 251 .getContext(request->payloadInstance); 252 response->sessionID = context.sessionID; 253 } 254 else 255 { 256 // No active payload - return session id as 0 257 response->sessionID = 0; 258 } 259 response->completionCode = IPMI_CC_OK; 260 return outPayload; 261 } 262 263 } // namespace command 264 265 } // namespace sol 266