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 catch (std::exception& e) 178 { 179 log<level::ERR>(e.what()); 180 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 181 return outPayload; 182 } 183 184 return outPayload; 185 } 186 187 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload, 188 const message::Handler& handler) 189 { 190 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 191 auto request = 192 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 193 auto response = 194 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 195 196 // SOL is the payload currently supported for payload status 197 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 198 { 199 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 200 return outPayload; 201 } 202 203 response->completionCode = IPMI_CC_OK; 204 205 constexpr size_t maxSolPayloadInstances = 1; 206 response->capacity = maxSolPayloadInstances; 207 208 // Currently we support only one SOL session 209 response->instance1 = 210 std::get<sol::Manager&>(singletonPool).isPayloadActive(1); 211 212 return outPayload; 213 } 214 215 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload, 216 const message::Handler& handler) 217 { 218 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 219 auto request = 220 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 221 auto response = 222 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 223 224 if (inPayload.size() != sizeof(GetPayloadInfoRequest)) 225 { 226 response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID; 227 return outPayload; 228 } 229 // SOL is the payload currently supported for payload status & only one 230 // instance of SOL is supported. 231 if (static_cast<uint8_t>(message::PayloadType::SOL) != 232 request->payloadType || 233 request->payloadInstance != 1) 234 { 235 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 236 return outPayload; 237 } 238 auto status = std::get<sol::Manager&>(singletonPool) 239 .isPayloadActive(request->payloadInstance); 240 241 if (status) 242 { 243 auto& context = std::get<sol::Manager&>(singletonPool) 244 .getContext(request->payloadInstance); 245 response->sessionID = context.sessionID; 246 } 247 else 248 { 249 // No active payload - return session id as 0 250 response->sessionID = 0; 251 } 252 response->completionCode = IPMI_CC_OK; 253 return outPayload; 254 } 255 256 } // namespace command 257 258 } // namespace sol 259