1 #include "payload_cmds.hpp"
2 
3 #include "main.hpp"
4 #include "sol/sol_manager.hpp"
5 #include "sol_cmds.hpp"
6 
7 #include <host-ipmid/ipmid-api.h>
8 
9 #include <phosphor-logging/log.hpp>
10 
11 namespace sol
12 {
13 
14 namespace command
15 {
16 
17 using namespace phosphor::logging;
18 
19 std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload,
20                                      const message::Handler& handler)
21 {
22     std::vector<uint8_t> outPayload(sizeof(ActivatePayloadResponse));
23     auto request =
24         reinterpret_cast<const ActivatePayloadRequest*>(inPayload.data());
25     auto response =
26         reinterpret_cast<ActivatePayloadResponse*>(outPayload.data());
27 
28     response->completionCode = IPMI_CC_OK;
29 
30     // SOL is the payload currently supported for activation.
31     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
32     {
33         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
34         return outPayload;
35     }
36 
37     if (!std::get<sol::Manager&>(singletonPool).enable)
38     {
39         response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
40         return outPayload;
41     }
42 
43     // Only one instance of SOL is currently supported.
44     if (request->payloadInstance != 1)
45     {
46         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
47         return outPayload;
48     }
49 
50     auto session = (std::get<session::Manager&>(singletonPool)
51                         .getSession(handler.sessionID))
52                        .lock();
53 
54     if (!request->encryption && session->isCryptAlgoEnabled())
55     {
56         response->completionCode = IPMI_CC_PAYLOAD_WITHOUT_ENCRYPTION;
57         return outPayload;
58     }
59 
60     auto status = std::get<sol::Manager&>(singletonPool)
61                       .isPayloadActive(request->payloadInstance);
62     if (status)
63     {
64         response->completionCode = IPMI_CC_PAYLOAD_ALREADY_ACTIVE;
65         return outPayload;
66     }
67 
68     // Set the current command's socket channel to the session
69     handler.setChannelInSession();
70 
71     // Start the SOL payload
72     try
73     {
74         std::get<sol::Manager&>(singletonPool)
75             .startPayloadInstance(request->payloadInstance, handler.sessionID);
76     }
77     catch (std::exception& e)
78     {
79         log<level::ERR>(e.what());
80         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
81         return outPayload;
82     }
83 
84     response->inPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
85     response->outPayloadSize = endian::to_ipmi<uint16_t>(MAX_PAYLOAD_SIZE);
86     response->portNum = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
87 
88     // VLAN addressing is not used
89     response->vlanNum = 0xFFFF;
90 
91     return outPayload;
92 }
93 
94 std::vector<uint8_t> deactivatePayload(const std::vector<uint8_t>& inPayload,
95                                        const message::Handler& handler)
96 {
97     std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse));
98     auto request =
99         reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data());
100     auto response =
101         reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data());
102 
103     response->completionCode = IPMI_CC_OK;
104 
105     // SOL is the payload currently supported for deactivation
106     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
107     {
108         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
109         return outPayload;
110     }
111 
112     // Only one instance of SOL is supported
113     if (request->payloadInstance != 1)
114     {
115         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
116         return outPayload;
117     }
118 
119     auto status = std::get<sol::Manager&>(singletonPool)
120                       .isPayloadActive(request->payloadInstance);
121     if (!status)
122     {
123         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
124         return outPayload;
125     }
126 
127     try
128     {
129         auto& context = std::get<sol::Manager&>(singletonPool)
130                             .getContext(request->payloadInstance);
131         auto sessionID = context.sessionID;
132 
133         std::get<sol::Manager&>(singletonPool)
134             .stopPayloadInstance(request->payloadInstance);
135 
136         try
137         {
138             activating(request->payloadInstance, sessionID);
139         }
140         catch (std::exception& e)
141         {
142             log<level::INFO>(e.what());
143             /*
144              * In case session has been closed (like in the case of inactivity
145              * timeout), then activating function would throw an exception,
146              * since sessionID is not found. IPMI success completion code is
147              * returned, since the session is closed.
148              */
149             return outPayload;
150         }
151 
152         auto check =
153             std::get<session::Manager&>(singletonPool).stopSession(sessionID);
154         if (!check)
155         {
156             response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
157         }
158     }
159     catch (std::exception& e)
160     {
161         log<level::ERR>(e.what());
162         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
163         return outPayload;
164     }
165 
166     return outPayload;
167 }
168 
169 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload,
170                                       const message::Handler& handler)
171 {
172     std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse));
173     auto request =
174         reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data());
175     auto response =
176         reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data());
177 
178     // SOL is the payload currently supported for payload status
179     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
180     {
181         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
182         return outPayload;
183     }
184 
185     response->completionCode = IPMI_CC_OK;
186     response->capacity = MAX_PAYLOAD_INSTANCES;
187 
188     // Currently we support only one SOL session
189     response->instance1 =
190         std::get<sol::Manager&>(singletonPool).isPayloadActive(1);
191 
192     return outPayload;
193 }
194 
195 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload,
196                                     const message::Handler& handler)
197 {
198     std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse));
199     auto request =
200         reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data());
201     auto response =
202         reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data());
203 
204     // SOL is the payload currently supported for payload status & only one
205     // instance of SOL is supported.
206     if (static_cast<uint8_t>(message::PayloadType::SOL) !=
207             request->payloadType ||
208         request->payloadInstance != 1)
209     {
210         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
211         return outPayload;
212     }
213 
214     auto status = std::get<sol::Manager&>(singletonPool)
215                       .isPayloadActive(request->payloadInstance);
216 
217     if (!status)
218     {
219         response->completionCode = IPMI_CC_RESPONSE_ERROR;
220         return outPayload;
221     }
222 
223     auto& context = std::get<sol::Manager&>(singletonPool)
224                         .getContext(request->payloadInstance);
225     response->sessionID = context.sessionID;
226 
227     return outPayload;
228 }
229 
230 } // namespace command
231 
232 } // namespace sol
233