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_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>
deactivatePayload(const std::vector<uint8_t> & inPayload,std::shared_ptr<message::Handler> & handler)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>
getPayloadStatus(const std::vector<uint8_t> & inPayload,std::shared_ptr<message::Handler> &)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>
getPayloadInfo(const std::vector<uint8_t> & inPayload,std::shared_ptr<message::Handler> &)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