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 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 std::get<sol::Manager&>(singletonPool) 45 .updateSOLParameter(ipmi::convertCurrentChannelNum( 46 ipmi::currentChNum, getInterfaceIndex())); 47 if (!std::get<sol::Manager&>(singletonPool).enable) 48 { 49 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 50 return outPayload; 51 } 52 53 // Only one instance of SOL is currently supported. 54 if (request->payloadInstance != 1) 55 { 56 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 57 return outPayload; 58 } 59 60 auto session = std::get<session::Manager&>(singletonPool) 61 .getSession(handler.sessionID); 62 63 if (!request->encryption && session->isCryptAlgoEnabled()) 64 { 65 response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION; 66 return outPayload; 67 } 68 69 // Is SOL Payload enabled for this user & channel. 70 auto userId = ipmi::ipmiUserGetUserId(session->userName); 71 ipmi::PayloadAccess payloadAccess = {}; 72 if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId, 73 payloadAccess) != IPMI_CC_OK) || 74 !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>( 75 message::PayloadType::SOL)])) 76 { 77 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 78 return outPayload; 79 } 80 81 auto status = std::get<sol::Manager&>(singletonPool) 82 .isPayloadActive(request->payloadInstance); 83 if (status) 84 { 85 response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; 86 return outPayload; 87 } 88 89 // Set the current command's socket channel to the session 90 handler.setChannelInSession(); 91 92 // Start the SOL payload 93 try 94 { 95 std::get<sol::Manager&>(singletonPool) 96 .startPayloadInstance(request->payloadInstance, handler.sessionID); 97 } 98 catch (std::exception& e) 99 { 100 log<level::ERR>(e.what()); 101 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 102 return outPayload; 103 } 104 105 response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 106 response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 107 response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); 108 109 // VLAN addressing is not used 110 response->vlanNum = 0xFFFF; 111 112 return outPayload; 113 } 114 115 std::vector<uint8_t> deactivatePayload(const std::vector<uint8_t>& inPayload, 116 const message::Handler& handler) 117 { 118 auto request = 119 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 120 if (inPayload.size() != sizeof(*request)) 121 { 122 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 123 return errorPayload; 124 } 125 126 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 127 auto response = 128 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 129 response->completionCode = IPMI_CC_OK; 130 131 // SOL is the payload currently supported for deactivation 132 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 133 { 134 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 135 return outPayload; 136 } 137 138 // Only one instance of SOL is supported 139 if (request->payloadInstance != 1) 140 { 141 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 142 return outPayload; 143 } 144 145 auto status = std::get<sol::Manager&>(singletonPool) 146 .isPayloadActive(request->payloadInstance); 147 if (!status) 148 { 149 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 150 return outPayload; 151 } 152 153 try 154 { 155 auto& context = std::get<sol::Manager&>(singletonPool) 156 .getContext(request->payloadInstance); 157 auto sessionID = context.sessionID; 158 159 std::get<sol::Manager&>(singletonPool) 160 .stopPayloadInstance(request->payloadInstance); 161 162 try 163 { 164 activating(request->payloadInstance, sessionID); 165 } 166 catch (std::exception& e) 167 { 168 log<level::INFO>(e.what()); 169 /* 170 * In case session has been closed (like in the case of inactivity 171 * timeout), then activating function would throw an exception, 172 * since sessionID is not found. IPMI success completion code is 173 * returned, since the session is closed. 174 */ 175 return outPayload; 176 } 177 } 178 catch (std::exception& e) 179 { 180 log<level::ERR>(e.what()); 181 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 182 return outPayload; 183 } 184 185 return outPayload; 186 } 187 188 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload, 189 const message::Handler& handler) 190 { 191 auto request = 192 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 193 if (inPayload.size() != sizeof(*request)) 194 { 195 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 196 return errorPayload; 197 } 198 199 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 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 auto request = 226 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 227 228 if (inPayload.size() != sizeof(*request)) 229 { 230 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 231 return errorPayload; 232 } 233 234 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 235 auto response = 236 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 237 238 // SOL is the payload currently supported for payload status & only one 239 // instance of SOL is supported. 240 if (static_cast<uint8_t>(message::PayloadType::SOL) != 241 request->payloadType || 242 request->payloadInstance != 1) 243 { 244 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 245 return outPayload; 246 } 247 auto status = std::get<sol::Manager&>(singletonPool) 248 .isPayloadActive(request->payloadInstance); 249 250 if (status) 251 { 252 auto& context = std::get<sol::Manager&>(singletonPool) 253 .getContext(request->payloadInstance); 254 response->sessionID = context.sessionID; 255 } 256 else 257 { 258 // No active payload - return session id as 0 259 response->sessionID = 0; 260 } 261 response->completionCode = IPMI_CC_OK; 262 return outPayload; 263 } 264 265 } // namespace command 266 267 } // namespace sol 268