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 const 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 (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> deactivatePayload(const std::vector<uint8_t>& inPayload, 113 const message::Handler& handler) 114 { 115 auto request = 116 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 117 if (inPayload.size() != sizeof(*request)) 118 { 119 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 120 return errorPayload; 121 } 122 123 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 124 auto response = 125 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 126 response->completionCode = IPMI_CC_OK; 127 128 // SOL is the payload currently supported for deactivation 129 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 130 { 131 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 132 return outPayload; 133 } 134 135 // Only one instance of SOL is supported 136 if (request->payloadInstance != 1) 137 { 138 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 139 return outPayload; 140 } 141 142 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 143 if (!status) 144 { 145 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 146 return outPayload; 147 } 148 149 try 150 { 151 auto& context = 152 sol::Manager::get().getContext(request->payloadInstance); 153 auto sessionID = context.sessionID; 154 155 sol::Manager::get().stopPayloadInstance(request->payloadInstance); 156 157 try 158 { 159 activating(request->payloadInstance, sessionID); 160 } 161 catch (std::exception& e) 162 { 163 log<level::INFO>(e.what()); 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 (std::exception& e) 174 { 175 log<level::ERR>(e.what()); 176 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 177 return outPayload; 178 } 179 180 return outPayload; 181 } 182 183 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload, 184 const message::Handler& handler) 185 { 186 auto request = 187 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 188 if (inPayload.size() != sizeof(*request)) 189 { 190 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 191 return errorPayload; 192 } 193 194 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 195 auto response = 196 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 197 198 // SOL is the payload currently supported for payload status 199 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 200 { 201 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 202 return outPayload; 203 } 204 205 response->completionCode = IPMI_CC_OK; 206 207 constexpr size_t maxSolPayloadInstances = 1; 208 response->capacity = maxSolPayloadInstances; 209 210 // Currently we support only one SOL session 211 response->instance1 = sol::Manager::get().isPayloadActive(1); 212 213 return outPayload; 214 } 215 216 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload, 217 const message::Handler& handler) 218 { 219 auto request = 220 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 221 222 if (inPayload.size() != sizeof(*request)) 223 { 224 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 225 return errorPayload; 226 } 227 228 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 229 auto response = 230 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 231 232 // SOL is the payload currently supported for payload status & only one 233 // instance of SOL is supported. 234 if (static_cast<uint8_t>(message::PayloadType::SOL) != 235 request->payloadType || 236 request->payloadInstance != 1) 237 { 238 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 239 return outPayload; 240 } 241 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 242 243 if (status) 244 { 245 auto& context = 246 sol::Manager::get().getContext(request->payloadInstance); 247 response->sessionID = context.sessionID; 248 } 249 else 250 { 251 // No active payload - return session id as 0 252 response->sessionID = 0; 253 } 254 response->completionCode = IPMI_CC_OK; 255 return outPayload; 256 } 257 258 } // namespace command 259 260 } // namespace sol 261