xref: /openbmc/phosphor-net-ipmid/command/payload_cmds.cpp (revision 12d199b27764496bfff8a45661239b1e509c336f)
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/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                                      std::shared_ptr<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     sol::Manager::get().updateSOLParameter(ipmi::convertCurrentChannelNum(
45         ipmi::currentChNum, getInterfaceIndex()));
46     if (!sol::Manager::get().enable)
47     {
48         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
49         return outPayload;
50     }
51 
52     // Only one instance of SOL is currently supported.
53     if (request->payloadInstance != 1)
54     {
55         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
56         return outPayload;
57     }
58 
59     auto session = session::Manager::get().getSession(handler->sessionID);
60 
61     if (!request->encryption && session->isCryptAlgoEnabled())
62     {
63         response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION;
64         return outPayload;
65     }
66 
67     // Is SOL Payload enabled for this user & channel.
68     auto userId = ipmi::ipmiUserGetUserId(session->userName);
69     ipmi::PayloadAccess payloadAccess = {};
70     if ((ipmi::ipmiUserGetUserPayloadAccess(session->channelNum(), userId,
71                                             payloadAccess) != IPMI_CC_OK) ||
72         !(payloadAccess.stdPayloadEnables1[static_cast<uint8_t>(
73             message::PayloadType::SOL)]))
74     {
75         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
76         return outPayload;
77     }
78 
79     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
80     if (status)
81     {
82         response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
83         return outPayload;
84     }
85 
86     // Set the current command's socket channel to the session
87     handler->setChannelInSession();
88 
89     // Start the SOL payload
90     try
91     {
92         sol::Manager::get().startPayloadInstance(request->payloadInstance,
93                                                  handler->sessionID);
94     }
95     catch (const std::exception& e)
96     {
97         log<level::ERR>(e.what());
98         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
99         return outPayload;
100     }
101 
102     response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
103     response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
104     response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
105 
106     // VLAN addressing is not used
107     response->vlanNum = 0xFFFF;
108 
109     return outPayload;
110 }
111 
112 std::vector<uint8_t>
113     deactivatePayload(const std::vector<uint8_t>& inPayload,
114                       std::shared_ptr<message::Handler>& handler)
115 {
116     auto request =
117         reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data());
118     if (inPayload.size() != sizeof(*request))
119     {
120         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
121         return errorPayload;
122     }
123 
124     std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse));
125     auto response =
126         reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data());
127     response->completionCode = IPMI_CC_OK;
128 
129     // SOL is the payload currently supported for deactivation
130     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
131     {
132         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
133         return outPayload;
134     }
135 
136     // Only one instance of SOL is supported
137     if (request->payloadInstance != 1)
138     {
139         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
140         return outPayload;
141     }
142 
143     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
144     if (!status)
145     {
146         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
147         return outPayload;
148     }
149 
150     try
151     {
152         auto& context =
153             sol::Manager::get().getContext(request->payloadInstance);
154         auto sessionID = context.sessionID;
155 
156         sol::Manager::get().stopPayloadInstance(request->payloadInstance);
157 
158         try
159         {
160             activating(request->payloadInstance, sessionID);
161         }
162         catch (const std::exception& e)
163         {
164             log<level::INFO>(e.what());
165             /*
166              * In case session has been closed (like in the case of inactivity
167              * timeout), then activating function would throw an exception,
168              * since sessionID is not found. IPMI success completion code is
169              * returned, since the session is closed.
170              */
171             return outPayload;
172         }
173     }
174     catch (const std::exception& e)
175     {
176         log<level::ERR>(e.what());
177         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
178         return outPayload;
179     }
180 
181     return outPayload;
182 }
183 
184 std::vector<uint8_t>
185     getPayloadStatus(const std::vector<uint8_t>& inPayload,
186                      std::shared_ptr<message::Handler>& handler)
187 {
188     auto request =
189         reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data());
190     if (inPayload.size() != sizeof(*request))
191     {
192         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
193         return errorPayload;
194     }
195 
196     std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse));
197     auto response =
198         reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data());
199 
200     // SOL is the payload currently supported for payload status
201     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
202     {
203         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
204         return outPayload;
205     }
206 
207     response->completionCode = IPMI_CC_OK;
208 
209     constexpr size_t maxSolPayloadInstances = 1;
210     response->capacity = maxSolPayloadInstances;
211 
212     // Currently we support only one SOL session
213     response->instance1 = sol::Manager::get().isPayloadActive(1);
214 
215     return outPayload;
216 }
217 
218 std::vector<uint8_t> 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