xref: /openbmc/phosphor-net-ipmid/command/payload_cmds.cpp (revision 7b7f25f70cdef22e626a41abe5bd8d950e14eff9)
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     // Is SOL Payload enabled for this user & channel.
66     auto userId = ipmi::ipmiUserGetUserId(session->userName);
67     ipmi::PayloadAccess payloadAccess = {};
68     if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId,
69                                             payloadAccess) != IPMI_CC_OK) ||
70         !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>(
71             message::PayloadType::SOL)]))
72     {
73         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
74         return outPayload;
75     }
76 
77     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
78     if (status)
79     {
80         response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
81         return outPayload;
82     }
83 
84     // Set the current command's socket channel to the session
85     handler->setChannelInSession();
86 
87     // Start the SOL payload
88     try
89     {
90         sol::Manager::get().startPayloadInstance(request->payloadInstance,
91                                                  handler->sessionID);
92     }
93     catch (const std::exception& e)
94     {
95         lg2::error("Failed to start SOL payload: {ERROR}", "ERROR", e);
96         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
97         return outPayload;
98     }
99 
100     response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
101     response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
102     response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
103 
104     // VLAN addressing is not used
105     response->vlanNum = 0xFFFF;
106 
107     return outPayload;
108 }
109 
110 std::vector<uint8_t>
111     deactivatePayload(const std::vector<uint8_t>& inPayload,
112                       std::shared_ptr<message::Handler>& /* handler */)
113 {
114     auto request =
115         reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data());
116     if (inPayload.size() != sizeof(*request))
117     {
118         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
119         return errorPayload;
120     }
121 
122     std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse));
123     auto response =
124         reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data());
125     response->completionCode = IPMI_CC_OK;
126 
127     // SOL is the payload currently supported for deactivation
128     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
129     {
130         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
131         return outPayload;
132     }
133 
134     // Only one instance of SOL is supported
135     if (request->payloadInstance != 1)
136     {
137         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
138         return outPayload;
139     }
140 
141     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
142     if (!status)
143     {
144         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
145         return outPayload;
146     }
147 
148     try
149     {
150         auto& context =
151             sol::Manager::get().getContext(request->payloadInstance);
152         auto sessionID = context.sessionID;
153 
154         sol::Manager::get().stopPayloadInstance(request->payloadInstance);
155 
156         try
157         {
158             activating(request->payloadInstance, sessionID);
159         }
160         catch (const std::exception& e)
161         {
162             lg2::info("Failed to call the activating method: {ERROR}", "ERROR",
163                       e);
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 (const std::exception& e)
174     {
175         lg2::error("Failed to call the getContext method: {ERROR}", "ERROR", e);
176         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
177         return outPayload;
178     }
179 
180     return outPayload;
181 }
182 
183 std::vector<uint8_t>
184     getPayloadStatus(const std::vector<uint8_t>& inPayload,
185                      std::shared_ptr<message::Handler>& /* handler */)
186 {
187     auto request =
188         reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data());
189     if (inPayload.size() != sizeof(*request))
190     {
191         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
192         return errorPayload;
193     }
194 
195     std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse));
196     auto response =
197         reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data());
198 
199     // SOL is the payload currently supported for payload status
200     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
201     {
202         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
203         return outPayload;
204     }
205 
206     response->completionCode = IPMI_CC_OK;
207 
208     constexpr size_t maxSolPayloadInstances = 1;
209     response->capacity = maxSolPayloadInstances;
210 
211     // Currently we support only one SOL session
212     response->instance1 = sol::Manager::get().isPayloadActive(1);
213 
214     return outPayload;
215 }
216 
217 std::vector<uint8_t>
218     getPayloadInfo(const std::vector<uint8_t>& inPayload,
219                    std::shared_ptr<message::Handler>& /* handler */)
220 {
221     auto request =
222         reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data());
223 
224     if (inPayload.size() != sizeof(*request))
225     {
226         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
227         return errorPayload;
228     }
229 
230     std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse));
231     auto response =
232         reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data());
233 
234     // SOL is the payload currently supported for payload status & only one
235     // instance of SOL is supported.
236     if (static_cast<uint8_t>(message::PayloadType::SOL) !=
237             request->payloadType ||
238         request->payloadInstance != 1)
239     {
240         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
241         return outPayload;
242     }
243     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
244 
245     if (status)
246     {
247         auto& context =
248             sol::Manager::get().getContext(request->payloadInstance);
249         response->sessionID = context.sessionID;
250     }
251     else
252     {
253         // No active payload - return session id as 0
254         response->sessionID = 0;
255     }
256     response->completionCode = IPMI_CC_OK;
257     return outPayload;
258 }
259 
260 } // namespace command
261 
262 } // namespace sol
263