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/lg2.hpp> 11 12 namespace sol 13 { 14 15 namespace command 16 { 17 18 std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload, 19 std::shared_ptr<message::Handler>& handler) 20 { 21 auto request = 22 reinterpret_cast<const ActivatePayloadRequest*>(inPayload.data()); 23 if (inPayload.size() != sizeof(*request)) 24 { 25 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 26 return errorPayload; 27 } 28 29 std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse)); 30 auto response = 31 reinterpret_cast<ActivatePayloadResponse*>(outPayload.data()); 32 33 response->completionCode = IPMI_CC_OK; 34 35 // SOL is the payload currently supported for activation. 36 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 37 { 38 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 39 return outPayload; 40 } 41 42 sol::Manager::get().updateSOLParameter(ipmi::convertCurrentChannelNum( 43 ipmi::currentChNum, getInterfaceIndex())); 44 if (!sol::Manager::get().enable) 45 { 46 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 47 return outPayload; 48 } 49 50 // Only one instance of SOL is currently supported. 51 if (request->payloadInstance != 1) 52 { 53 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 54 return outPayload; 55 } 56 57 auto session = session::Manager::get().getSession(handler->sessionID); 58 59 if (!request->encryption && session->isCryptAlgoEnabled()) 60 { 61 response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION; 62 return outPayload; 63 } 64 65 if (session->currentPrivilege() < 66 static_cast<uint8_t>(sol::Manager::get().solMinPrivilege)) 67 { 68 response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; 69 return outPayload; 70 } 71 72 // Is SOL Payload enabled for this user & channel. 73 auto userId = ipmi::ipmiUserGetUserId(session->userName); 74 ipmi::PayloadAccess payloadAccess = {}; 75 if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId, 76 payloadAccess) != IPMI_CC_OK) || 77 !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>( 78 message::PayloadType::SOL)])) 79 { 80 response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; 81 return outPayload; 82 } 83 84 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 85 if (status) 86 { 87 response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE; 88 return outPayload; 89 } 90 91 // Set the current command's socket channel to the session 92 handler->setChannelInSession(); 93 94 // Start the SOL payload 95 try 96 { 97 sol::Manager::get().startPayloadInstance(request->payloadInstance, 98 handler->sessionID); 99 } 100 catch (const std::exception& e) 101 { 102 lg2::error("Failed to start SOL payload: {ERROR}", "ERROR", e); 103 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 104 return outPayload; 105 } 106 107 response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 108 response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE); 109 response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); 110 111 // VLAN addressing is not used 112 response->vlanNum = 0xFFFF; 113 114 return outPayload; 115 } 116 117 std::vector<uint8_t> 118 deactivatePayload(const std::vector<uint8_t>& inPayload, 119 std::shared_ptr<message::Handler>& handler) 120 { 121 auto request = 122 reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data()); 123 if (inPayload.size() != sizeof(*request)) 124 { 125 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 126 return errorPayload; 127 } 128 129 std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse)); 130 auto response = 131 reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data()); 132 response->completionCode = IPMI_CC_OK; 133 134 // SOL is the payload currently supported for deactivation 135 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 136 { 137 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 138 return outPayload; 139 } 140 141 // Only one instance of SOL is supported 142 if (request->payloadInstance != 1) 143 { 144 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 145 return outPayload; 146 } 147 148 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 149 if (!status) 150 { 151 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 152 return outPayload; 153 } 154 155 auto currentSession = 156 session::Manager::get().getSession(handler->sessionID); 157 auto solSessionID = 158 sol::Manager::get().getContext(request->payloadInstance).sessionID; 159 auto solActiveSession = 160 sol::Manager::get().getContext(request->payloadInstance).session; 161 // The session owner or the ADMIN could deactivate the session 162 if (currentSession->userName != solActiveSession->userName && 163 currentSession->currentPrivilege() != 164 static_cast<uint8_t>(session::Privilege::ADMIN)) 165 { 166 response->completionCode = IPMI_CC_INSUFFICIENT_PRIVILEGE; 167 return outPayload; 168 } 169 170 try 171 { 172 sol::Manager::get().stopPayloadInstance(request->payloadInstance); 173 174 try 175 { 176 activating(request->payloadInstance, solSessionID); 177 } 178 catch (const std::exception& e) 179 { 180 lg2::info("Failed to call the activating method: {ERROR}", "ERROR", 181 e); 182 /* 183 * In case session has been closed (like in the case of inactivity 184 * timeout), then activating function would throw an exception, 185 * since solSessionID is not found. As session is already closed, 186 * returning IPMI status code for Payload already deactivated 187 * as BMC automatically deactivates all active payloads when 188 * session is terminated. 189 */ 190 response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED; 191 return outPayload; 192 } 193 } 194 catch (const std::exception& e) 195 { 196 lg2::error("Failed to call the getContext method: {ERROR}", "ERROR", e); 197 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 198 return outPayload; 199 } 200 201 return outPayload; 202 } 203 204 std::vector<uint8_t> 205 getPayloadStatus(const std::vector<uint8_t>& inPayload, 206 std::shared_ptr<message::Handler>& /* handler */) 207 { 208 auto request = 209 reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data()); 210 if (inPayload.size() != sizeof(*request)) 211 { 212 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 213 return errorPayload; 214 } 215 216 std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse)); 217 auto response = 218 reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data()); 219 220 // SOL is the payload currently supported for payload status 221 if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType) 222 { 223 response->completionCode = IPMI_CC_UNSPECIFIED_ERROR; 224 return outPayload; 225 } 226 227 response->completionCode = IPMI_CC_OK; 228 229 constexpr size_t maxSolPayloadInstances = 1; 230 response->capacity = maxSolPayloadInstances; 231 232 // Currently we support only one SOL session 233 response->instance1 = sol::Manager::get().isPayloadActive(1); 234 235 return outPayload; 236 } 237 238 std::vector<uint8_t> 239 getPayloadInfo(const std::vector<uint8_t>& inPayload, 240 std::shared_ptr<message::Handler>& /* handler */) 241 { 242 auto request = 243 reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data()); 244 245 if (inPayload.size() != sizeof(*request)) 246 { 247 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 248 return errorPayload; 249 } 250 251 std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse)); 252 auto response = 253 reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data()); 254 255 // SOL is the payload currently supported for payload status & only one 256 // instance of SOL is supported. 257 if (static_cast<uint8_t>(message::PayloadType::SOL) != 258 request->payloadType || 259 request->payloadInstance != 1) 260 { 261 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 262 return outPayload; 263 } 264 auto status = sol::Manager::get().isPayloadActive(request->payloadInstance); 265 266 if (status) 267 { 268 auto& context = 269 sol::Manager::get().getContext(request->payloadInstance); 270 response->sessionID = context.sessionID; 271 } 272 else 273 { 274 // No active payload - return session id as 0 275 response->sessionID = 0; 276 } 277 response->completionCode = IPMI_CC_OK; 278 return outPayload; 279 } 280 281 } // namespace command 282 283 } // namespace sol 284