1 #include "payload_cmds.hpp"
2 
3 #include "main.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                                      const message::Handler& handler)
22 {
23     std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse));
24     auto request =
25         reinterpret_cast<const ActivatePayloadRequest*>(inPayload.data());
26     auto response =
27         reinterpret_cast<ActivatePayloadResponse*>(outPayload.data());
28 
29     if (inPayload.size() != sizeof(ActivatePayloadRequest))
30     {
31         response->completionCode = ipmi::ccReqDataLenInvalid;
32         outPayload.resize(sizeof(response->completionCode));
33         return outPayload;
34     }
35 
36     response->completionCode = IPMI_CC_OK;
37 
38     // SOL is the payload currently supported for activation.
39     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
40     {
41         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
42         return outPayload;
43     }
44 
45     if (!std::get<sol::Manager&>(singletonPool).enable)
46     {
47         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
48         return outPayload;
49     }
50 
51     // Only one instance of SOL is currently supported.
52     if (request->payloadInstance != 1)
53     {
54         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
55         return outPayload;
56     }
57 
58     auto session = std::get<session::Manager&>(singletonPool)
59                        .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 = std::get<sol::Manager&>(singletonPool)
80                       .isPayloadActive(request->payloadInstance);
81     if (status)
82     {
83         response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
84         return outPayload;
85     }
86 
87     // Set the current command's socket channel to the session
88     handler.setChannelInSession();
89 
90     // Start the SOL payload
91     try
92     {
93         std::get<sol::Manager&>(singletonPool)
94             .startPayloadInstance(request->payloadInstance, handler.sessionID);
95     }
96     catch (std::exception& e)
97     {
98         log<level::ERR>(e.what());
99         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
100         return outPayload;
101     }
102 
103     response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
104     response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
105     response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
106 
107     // VLAN addressing is not used
108     response->vlanNum = 0xFFFF;
109 
110     return outPayload;
111 }
112 
113 std::vector<uint8_t> deactivatePayload(const std::vector<uint8_t>& inPayload,
114                                        const message::Handler& handler)
115 {
116     std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse));
117     auto request =
118         reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data());
119     auto response =
120         reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data());
121 
122     response->completionCode = IPMI_CC_OK;
123 
124     if (inPayload.size() != sizeof(DeactivatePayloadRequest))
125     {
126         response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
127         return outPayload;
128     }
129 
130     // SOL is the payload currently supported for deactivation
131     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
132     {
133         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
134         return outPayload;
135     }
136 
137     // Only one instance of SOL is supported
138     if (request->payloadInstance != 1)
139     {
140         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
141         return outPayload;
142     }
143 
144     auto status = std::get<sol::Manager&>(singletonPool)
145                       .isPayloadActive(request->payloadInstance);
146     if (!status)
147     {
148         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
149         return outPayload;
150     }
151 
152     try
153     {
154         auto& context = std::get<sol::Manager&>(singletonPool)
155                             .getContext(request->payloadInstance);
156         auto sessionID = context.sessionID;
157 
158         std::get<sol::Manager&>(singletonPool)
159             .stopPayloadInstance(request->payloadInstance);
160 
161         try
162         {
163             activating(request->payloadInstance, sessionID);
164         }
165         catch (std::exception& e)
166         {
167             log<level::INFO>(e.what());
168             /*
169              * In case session has been closed (like in the case of inactivity
170              * timeout), then activating function would throw an exception,
171              * since sessionID is not found. IPMI success completion code is
172              * returned, since the session is closed.
173              */
174             return outPayload;
175         }
176     }
177     catch (std::exception& e)
178     {
179         log<level::ERR>(e.what());
180         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
181         return outPayload;
182     }
183 
184     return outPayload;
185 }
186 
187 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload,
188                                       const message::Handler& handler)
189 {
190     std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse));
191     auto request =
192         reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data());
193     auto response =
194         reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data());
195 
196     // SOL is the payload currently supported for payload status
197     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
198     {
199         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
200         return outPayload;
201     }
202 
203     response->completionCode = IPMI_CC_OK;
204 
205     constexpr size_t maxSolPayloadInstances = 1;
206     response->capacity = maxSolPayloadInstances;
207 
208     // Currently we support only one SOL session
209     response->instance1 =
210         std::get<sol::Manager&>(singletonPool).isPayloadActive(1);
211 
212     return outPayload;
213 }
214 
215 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload,
216                                     const message::Handler& handler)
217 {
218     std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse));
219     auto request =
220         reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data());
221     auto response =
222         reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data());
223 
224     if (inPayload.size() != sizeof(GetPayloadInfoRequest))
225     {
226         response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
227         return outPayload;
228     }
229     // SOL is the payload currently supported for payload status & only one
230     // instance of SOL is supported.
231     if (static_cast<uint8_t>(message::PayloadType::SOL) !=
232             request->payloadType ||
233         request->payloadInstance != 1)
234     {
235         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
236         return outPayload;
237     }
238     auto status = std::get<sol::Manager&>(singletonPool)
239                       .isPayloadActive(request->payloadInstance);
240 
241     if (status)
242     {
243         auto& context = std::get<sol::Manager&>(singletonPool)
244                             .getContext(request->payloadInstance);
245         response->sessionID = context.sessionID;
246     }
247     else
248     {
249         // No active payload - return session id as 0
250         response->sessionID = 0;
251     }
252     response->completionCode = IPMI_CC_OK;
253     return outPayload;
254 }
255 
256 } // namespace command
257 
258 } // namespace sol
259