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