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                                      const 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 (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> deactivatePayload(const std::vector<uint8_t>& inPayload,
113                                        const message::Handler& handler)
114 {
115     auto request =
116         reinterpret_cast<const DeactivatePayloadRequest*>(inPayload.data());
117     if (inPayload.size() != sizeof(*request))
118     {
119         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
120         return errorPayload;
121     }
122 
123     std::vector<uint8_t> outPayload(sizeof(DeactivatePayloadResponse));
124     auto response =
125         reinterpret_cast<DeactivatePayloadResponse*>(outPayload.data());
126     response->completionCode = IPMI_CC_OK;
127 
128     // SOL is the payload currently supported for deactivation
129     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
130     {
131         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
132         return outPayload;
133     }
134 
135     // Only one instance of SOL is supported
136     if (request->payloadInstance != 1)
137     {
138         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
139         return outPayload;
140     }
141 
142     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
143     if (!status)
144     {
145         response->completionCode = IPMI_CC_PAYLOAD_DEACTIVATED;
146         return outPayload;
147     }
148 
149     try
150     {
151         auto& context =
152             sol::Manager::get().getContext(request->payloadInstance);
153         auto sessionID = context.sessionID;
154 
155         sol::Manager::get().stopPayloadInstance(request->payloadInstance);
156 
157         try
158         {
159             activating(request->payloadInstance, sessionID);
160         }
161         catch (std::exception& e)
162         {
163             log<level::INFO>(e.what());
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 (std::exception& e)
174     {
175         log<level::ERR>(e.what());
176         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
177         return outPayload;
178     }
179 
180     return outPayload;
181 }
182 
183 std::vector<uint8_t> getPayloadStatus(const std::vector<uint8_t>& inPayload,
184                                       const message::Handler& handler)
185 {
186     auto request =
187         reinterpret_cast<const GetPayloadStatusRequest*>(inPayload.data());
188     if (inPayload.size() != sizeof(*request))
189     {
190         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
191         return errorPayload;
192     }
193 
194     std::vector<uint8_t> outPayload(sizeof(GetPayloadStatusResponse));
195     auto response =
196         reinterpret_cast<GetPayloadStatusResponse*>(outPayload.data());
197 
198     // SOL is the payload currently supported for payload status
199     if (static_cast<uint8_t>(message::PayloadType::SOL) != request->payloadType)
200     {
201         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
202         return outPayload;
203     }
204 
205     response->completionCode = IPMI_CC_OK;
206 
207     constexpr size_t maxSolPayloadInstances = 1;
208     response->capacity = maxSolPayloadInstances;
209 
210     // Currently we support only one SOL session
211     response->instance1 = sol::Manager::get().isPayloadActive(1);
212 
213     return outPayload;
214 }
215 
216 std::vector<uint8_t> getPayloadInfo(const std::vector<uint8_t>& inPayload,
217                                     const message::Handler& handler)
218 {
219     auto request =
220         reinterpret_cast<const GetPayloadInfoRequest*>(inPayload.data());
221 
222     if (inPayload.size() != sizeof(*request))
223     {
224         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
225         return errorPayload;
226     }
227 
228     std::vector<uint8_t> outPayload(sizeof(GetPayloadInfoResponse));
229     auto response =
230         reinterpret_cast<GetPayloadInfoResponse*>(outPayload.data());
231 
232     // SOL is the payload currently supported for payload status & only one
233     // instance of SOL is supported.
234     if (static_cast<uint8_t>(message::PayloadType::SOL) !=
235             request->payloadType ||
236         request->payloadInstance != 1)
237     {
238         response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
239         return outPayload;
240     }
241     auto status = sol::Manager::get().isPayloadActive(request->payloadInstance);
242 
243     if (status)
244     {
245         auto& context =
246             sol::Manager::get().getContext(request->payloadInstance);
247         response->sessionID = context.sessionID;
248     }
249     else
250     {
251         // No active payload - return session id as 0
252         response->sessionID = 0;
253     }
254     response->completionCode = IPMI_CC_OK;
255     return outPayload;
256 }
257 
258 } // namespace command
259 
260 } // namespace sol
261