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