xref: /openbmc/phosphor-ipmi-blobs/ipmi.cpp (revision 97e69ca106fc2415f89370eea36fb674435b5bdb)
1ef3aeadcSPatrick Venture /*
2ef3aeadcSPatrick Venture  * Copyright 2018 Google Inc.
3ef3aeadcSPatrick Venture  *
4ef3aeadcSPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
5ef3aeadcSPatrick Venture  * you may not use this file except in compliance with the License.
6ef3aeadcSPatrick Venture  * You may obtain a copy of the License at
7ef3aeadcSPatrick Venture  *
8ef3aeadcSPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
9ef3aeadcSPatrick Venture  *
10ef3aeadcSPatrick Venture  * Unless required by applicable law or agreed to in writing, software
11ef3aeadcSPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
12ef3aeadcSPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef3aeadcSPatrick Venture  * See the License for the specific language governing permissions and
14ef3aeadcSPatrick Venture  * limitations under the License.
15ef3aeadcSPatrick Venture  */
16ef3aeadcSPatrick Venture 
17ef3aeadcSPatrick Venture #include "ipmi.hpp"
18ef3aeadcSPatrick Venture 
19ef3aeadcSPatrick Venture #include <cstring>
20067ece15SWilly Tu #include <span>
21ef3aeadcSPatrick Venture #include <string>
22ef3aeadcSPatrick Venture #include <unordered_map>
23ef3aeadcSPatrick Venture 
24ef3aeadcSPatrick Venture namespace blobs
25ef3aeadcSPatrick Venture {
26ef3aeadcSPatrick Venture 
validateRequestLength(BlobOEMCommands command,size_t requestLen)27ef3aeadcSPatrick Venture bool validateRequestLength(BlobOEMCommands command, size_t requestLen)
28ef3aeadcSPatrick Venture {
29ef3aeadcSPatrick Venture     /* The smallest string is one letter and the nul-terminator. */
30ef3aeadcSPatrick Venture     static const int kMinStrLen = 2;
31ef3aeadcSPatrick Venture 
32ef3aeadcSPatrick Venture     static const std::unordered_map<BlobOEMCommands, size_t> minimumLengths = {
33ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobEnumerate, sizeof(struct BmcBlobEnumerateTx)},
34ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobOpen,
35ef3aeadcSPatrick Venture          sizeof(struct BmcBlobOpenTx) + kMinStrLen},
36ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobClose, sizeof(struct BmcBlobCloseTx)},
37ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobDelete,
38ef3aeadcSPatrick Venture          sizeof(struct BmcBlobDeleteTx) + kMinStrLen},
39ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobStat,
40ef3aeadcSPatrick Venture          sizeof(struct BmcBlobStatTx) + kMinStrLen},
41ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobSessionStat,
42ef3aeadcSPatrick Venture          sizeof(struct BmcBlobSessionStatTx)},
43ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobCommit, sizeof(struct BmcBlobCommitTx)},
44ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobRead, sizeof(struct BmcBlobReadTx)},
45ef3aeadcSPatrick Venture         {BlobOEMCommands::bmcBlobWrite,
46ef3aeadcSPatrick Venture          sizeof(struct BmcBlobWriteTx) + sizeof(uint8_t)},
475c4b17b2SPatrick Venture         {BlobOEMCommands::bmcBlobWriteMeta,
485c4b17b2SPatrick Venture          sizeof(struct BmcBlobWriteMetaTx) + sizeof(uint8_t)},
49ef3aeadcSPatrick Venture     };
50ef3aeadcSPatrick Venture 
51ef3aeadcSPatrick Venture     auto results = minimumLengths.find(command);
52ef3aeadcSPatrick Venture     if (results == minimumLengths.end())
53ef3aeadcSPatrick Venture     {
54ef3aeadcSPatrick Venture         /* Valid length by default if we don't care. */
55ef3aeadcSPatrick Venture         return true;
56ef3aeadcSPatrick Venture     }
57ef3aeadcSPatrick Venture 
58ef3aeadcSPatrick Venture     /* If the request is shorter than the minimum, it's invalid. */
59ef3aeadcSPatrick Venture     if (requestLen < results->second)
60ef3aeadcSPatrick Venture     {
61ef3aeadcSPatrick Venture         return false;
62ef3aeadcSPatrick Venture     }
63ef3aeadcSPatrick Venture 
64ef3aeadcSPatrick Venture     return true;
65ef3aeadcSPatrick Venture }
66ef3aeadcSPatrick Venture 
stringFromBuffer(std::span<const uint8_t> data)67067ece15SWilly Tu std::string stringFromBuffer(std::span<const uint8_t> data)
68ef3aeadcSPatrick Venture {
69067ece15SWilly Tu     if (data.empty() || data.back() != '\0')
70ef3aeadcSPatrick Venture     {
71067ece15SWilly Tu         return std::string();
72ef3aeadcSPatrick Venture     }
73ef3aeadcSPatrick Venture 
74067ece15SWilly Tu     // Last index is nul-terminator.
75067ece15SWilly Tu     return std::string(data.begin(), data.end() - 1);
76ef3aeadcSPatrick Venture }
77ef3aeadcSPatrick Venture 
getBlobCount(ManagerInterface * mgr,std::span<const uint8_t>)78067ece15SWilly Tu Resp getBlobCount(ManagerInterface* mgr, std::span<const uint8_t>)
79ef3aeadcSPatrick Venture {
80ef3aeadcSPatrick Venture     struct BmcBlobCountRx resp;
81ef3aeadcSPatrick Venture     resp.crc = 0;
82ef3aeadcSPatrick Venture     resp.blobCount = mgr->buildBlobList();
83ef3aeadcSPatrick Venture 
84ef3aeadcSPatrick Venture     /* Copy the response into the reply buffer */
85067ece15SWilly Tu     std::vector<uint8_t> output(sizeof(BmcBlobCountRx), 0);
86067ece15SWilly Tu     std::memcpy(output.data(), &resp, sizeof(resp));
87ef3aeadcSPatrick Venture 
88067ece15SWilly Tu     return ipmi::responseSuccess(output);
89ef3aeadcSPatrick Venture }
90ef3aeadcSPatrick Venture 
enumerateBlob(ManagerInterface * mgr,std::span<const uint8_t> data)91067ece15SWilly Tu Resp enumerateBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
92ef3aeadcSPatrick Venture {
93ef3aeadcSPatrick Venture     /* Verify datalen is >= sizeof(request) */
94ef3aeadcSPatrick Venture     struct BmcBlobEnumerateTx request;
95ef3aeadcSPatrick Venture 
96067ece15SWilly Tu     std::memcpy(&request, data.data(), sizeof(request));
97ef3aeadcSPatrick Venture 
98ef3aeadcSPatrick Venture     std::string blobId = mgr->getBlobId(request.blobIdx);
993d1fdfaaSWilly Tu     if (blobId.empty())
100ef3aeadcSPatrick Venture     {
101067ece15SWilly Tu         return ipmi::responseInvalidFieldRequest();
102ef3aeadcSPatrick Venture     }
103ef3aeadcSPatrick Venture 
104067ece15SWilly Tu     std::vector<uint8_t> output(sizeof(BmcBlobEnumerateRx), 0);
105067ece15SWilly Tu     output.insert(output.end(), blobId.c_str(),
106067ece15SWilly Tu                   blobId.c_str() + blobId.length() + 1);
107067ece15SWilly Tu     return ipmi::responseSuccess(output);
108ef3aeadcSPatrick Venture }
109ef3aeadcSPatrick Venture 
openBlob(ManagerInterface * mgr,std::span<const uint8_t> data)110067ece15SWilly Tu Resp openBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
111ef3aeadcSPatrick Venture {
112067ece15SWilly Tu     auto request = reinterpret_cast<const struct BmcBlobOpenTx*>(data.data());
113ef3aeadcSPatrick Venture     uint16_t session;
114ef3aeadcSPatrick Venture 
115067ece15SWilly Tu     std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobOpenTx)));
116ef3aeadcSPatrick Venture     if (path.empty())
117ef3aeadcSPatrick Venture     {
118067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
119ef3aeadcSPatrick Venture     }
120ef3aeadcSPatrick Venture 
121ef3aeadcSPatrick Venture     /* Attempt to open. */
122ef3aeadcSPatrick Venture     if (!mgr->open(request->flags, path, &session))
123ef3aeadcSPatrick Venture     {
124067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
125ef3aeadcSPatrick Venture     }
126ef3aeadcSPatrick Venture 
127ef3aeadcSPatrick Venture     struct BmcBlobOpenRx reply;
128ef3aeadcSPatrick Venture     reply.crc = 0;
129ef3aeadcSPatrick Venture     reply.sessionId = session;
130ef3aeadcSPatrick Venture 
131067ece15SWilly Tu     std::vector<uint8_t> output(sizeof(BmcBlobOpenRx), 0);
132067ece15SWilly Tu     std::memcpy(output.data(), &reply, sizeof(reply));
133067ece15SWilly Tu     return ipmi::responseSuccess(output);
134ef3aeadcSPatrick Venture }
135ef3aeadcSPatrick Venture 
closeBlob(ManagerInterface * mgr,std::span<const uint8_t> data)136067ece15SWilly Tu Resp closeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
137ef3aeadcSPatrick Venture {
138ef3aeadcSPatrick Venture     struct BmcBlobCloseTx request;
139067ece15SWilly Tu     if (data.size() < sizeof(request))
140067ece15SWilly Tu     {
141067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
142067ece15SWilly Tu     }
143067ece15SWilly Tu     std::memcpy(&request, data.data(), sizeof(request));
144ef3aeadcSPatrick Venture 
145ef3aeadcSPatrick Venture     /* Attempt to close. */
146ef3aeadcSPatrick Venture     if (!mgr->close(request.sessionId))
147ef3aeadcSPatrick Venture     {
148067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
149ef3aeadcSPatrick Venture     }
150ef3aeadcSPatrick Venture 
151067ece15SWilly Tu     return ipmi::responseSuccess(std::vector<uint8_t>{});
152ef3aeadcSPatrick Venture }
153ef3aeadcSPatrick Venture 
deleteBlob(ManagerInterface * mgr,std::span<const uint8_t> data)154067ece15SWilly Tu Resp deleteBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
155ef3aeadcSPatrick Venture {
156067ece15SWilly Tu     std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobDeleteTx)));
157ef3aeadcSPatrick Venture     if (path.empty())
158ef3aeadcSPatrick Venture     {
159067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
160ef3aeadcSPatrick Venture     }
161ef3aeadcSPatrick Venture 
162ef3aeadcSPatrick Venture     /* Attempt to delete. */
163ef3aeadcSPatrick Venture     if (!mgr->deleteBlob(path))
164ef3aeadcSPatrick Venture     {
165067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
166ef3aeadcSPatrick Venture     }
167ef3aeadcSPatrick Venture 
168067ece15SWilly Tu     return ipmi::responseSuccess(std::vector<uint8_t>{});
169ef3aeadcSPatrick Venture }
170ef3aeadcSPatrick Venture 
returnStatBlob(BlobMeta * meta)171067ece15SWilly Tu static Resp returnStatBlob(BlobMeta* meta)
172ef3aeadcSPatrick Venture {
173ef3aeadcSPatrick Venture     struct BmcBlobStatRx reply;
174ef3aeadcSPatrick Venture     reply.crc = 0;
175ef3aeadcSPatrick Venture     reply.blobState = meta->blobState;
176ef3aeadcSPatrick Venture     reply.size = meta->size;
177ef3aeadcSPatrick Venture     reply.metadataLen = meta->metadata.size();
178ef3aeadcSPatrick Venture 
179067ece15SWilly Tu     std::vector<uint8_t> output(sizeof(BmcBlobStatRx), 0);
180067ece15SWilly Tu     std::memcpy(output.data(), &reply, sizeof(reply));
181ef3aeadcSPatrick Venture 
182067ece15SWilly Tu     /* If there is metadata, insert it to output. */
1833d1fdfaaSWilly Tu     if (!meta->metadata.empty())
184ef3aeadcSPatrick Venture     {
185067ece15SWilly Tu         output.insert(output.end(), meta->metadata.begin(),
186067ece15SWilly Tu                       meta->metadata.end());
187067ece15SWilly Tu     }
188067ece15SWilly Tu     return ipmi::responseSuccess(output);
189ef3aeadcSPatrick Venture }
190ef3aeadcSPatrick Venture 
statBlob(ManagerInterface * mgr,std::span<const uint8_t> data)191067ece15SWilly Tu Resp statBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
192ef3aeadcSPatrick Venture {
193067ece15SWilly Tu     std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobStatTx)));
194ef3aeadcSPatrick Venture     if (path.empty())
195ef3aeadcSPatrick Venture     {
196067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
197ef3aeadcSPatrick Venture     }
198ef3aeadcSPatrick Venture 
199ef3aeadcSPatrick Venture     /* Attempt to stat. */
2008bc11779SPatrick Venture     BlobMeta meta;
201ef3aeadcSPatrick Venture     if (!mgr->stat(path, &meta))
202ef3aeadcSPatrick Venture     {
203067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
204ef3aeadcSPatrick Venture     }
205ef3aeadcSPatrick Venture 
206067ece15SWilly Tu     return returnStatBlob(&meta);
207ef3aeadcSPatrick Venture }
208ef3aeadcSPatrick Venture 
sessionStatBlob(ManagerInterface * mgr,std::span<const uint8_t> data)209067ece15SWilly Tu Resp sessionStatBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
210ef3aeadcSPatrick Venture {
211ef3aeadcSPatrick Venture     struct BmcBlobSessionStatTx request;
212067ece15SWilly Tu     if (data.size() < sizeof(request))
213067ece15SWilly Tu     {
214067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
215067ece15SWilly Tu     }
216067ece15SWilly Tu     std::memcpy(&request, data.data(), sizeof(request));
217ef3aeadcSPatrick Venture 
218ef3aeadcSPatrick Venture     /* Attempt to stat. */
2198bc11779SPatrick Venture     BlobMeta meta;
220ef3aeadcSPatrick Venture 
221ef3aeadcSPatrick Venture     if (!mgr->stat(request.sessionId, &meta))
222ef3aeadcSPatrick Venture     {
223067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
224ef3aeadcSPatrick Venture     }
225ef3aeadcSPatrick Venture 
226067ece15SWilly Tu     return returnStatBlob(&meta);
227ef3aeadcSPatrick Venture }
228ef3aeadcSPatrick Venture 
commitBlob(ManagerInterface * mgr,std::span<const uint8_t> data)229067ece15SWilly Tu Resp commitBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
230ef3aeadcSPatrick Venture {
231067ece15SWilly Tu     auto request = reinterpret_cast<const struct BmcBlobCommitTx*>(data.data());
232ef3aeadcSPatrick Venture 
233ef3aeadcSPatrick Venture     /* Sanity check the commitDataLen */
234067ece15SWilly Tu     if (request->commitDataLen > (data.size() - sizeof(struct BmcBlobCommitTx)))
235ef3aeadcSPatrick Venture     {
236067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
237ef3aeadcSPatrick Venture     }
238ef3aeadcSPatrick Venture 
239067ece15SWilly Tu     data = data.subspan(sizeof(struct BmcBlobCommitTx), request->commitDataLen);
240ef3aeadcSPatrick Venture 
241067ece15SWilly Tu     if (!mgr->commit(request->sessionId,
242067ece15SWilly Tu                      std::vector<uint8_t>(data.begin(), data.end())))
243ef3aeadcSPatrick Venture     {
244067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
245ef3aeadcSPatrick Venture     }
246ef3aeadcSPatrick Venture 
247067ece15SWilly Tu     return ipmi::responseSuccess(std::vector<uint8_t>{});
248ef3aeadcSPatrick Venture }
249ef3aeadcSPatrick Venture 
readBlob(ManagerInterface * mgr,std::span<const uint8_t> data)250067ece15SWilly Tu Resp readBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
251ef3aeadcSPatrick Venture {
252ef3aeadcSPatrick Venture     struct BmcBlobReadTx request;
253067ece15SWilly Tu     if (data.size() < sizeof(request))
254067ece15SWilly Tu     {
255067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
256067ece15SWilly Tu     }
257067ece15SWilly Tu     std::memcpy(&request, data.data(), sizeof(request));
258ef3aeadcSPatrick Venture 
259*97e69ca1SPatrick Williams     std::vector<uint8_t> result =
260*97e69ca1SPatrick Williams         mgr->read(request.sessionId, request.offset, request.requestedSize);
261ef3aeadcSPatrick Venture 
262ef3aeadcSPatrick Venture     /* If the Read fails, it returns success but with only the crc and 0 bytes
263ef3aeadcSPatrick Venture      * of data.
264ef3aeadcSPatrick Venture      * If there was data returned, copy into the reply buffer.
265ef3aeadcSPatrick Venture      */
266067ece15SWilly Tu     std::vector<uint8_t> output(sizeof(BmcBlobReadRx), 0);
267ef3aeadcSPatrick Venture 
2683d1fdfaaSWilly Tu     if (!result.empty())
269ef3aeadcSPatrick Venture     {
270067ece15SWilly Tu         output.insert(output.end(), result.begin(), result.end());
271ef3aeadcSPatrick Venture     }
272ef3aeadcSPatrick Venture 
273067ece15SWilly Tu     return ipmi::responseSuccess(output);
274ef3aeadcSPatrick Venture }
275ef3aeadcSPatrick Venture 
writeBlob(ManagerInterface * mgr,std::span<const uint8_t> data)276067ece15SWilly Tu Resp writeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
277ef3aeadcSPatrick Venture {
278067ece15SWilly Tu     auto request = reinterpret_cast<const struct BmcBlobWriteTx*>(data.data());
279067ece15SWilly Tu     data = data.subspan(sizeof(struct BmcBlobWriteTx));
280ef3aeadcSPatrick Venture 
281ef3aeadcSPatrick Venture     /* Attempt to write the bytes. */
282067ece15SWilly Tu     if (!mgr->write(request->sessionId, request->offset,
283067ece15SWilly Tu                     std::vector<uint8_t>(data.begin(), data.end())))
284ef3aeadcSPatrick Venture     {
285067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
286ef3aeadcSPatrick Venture     }
287ef3aeadcSPatrick Venture 
288067ece15SWilly Tu     return ipmi::responseSuccess(std::vector<uint8_t>{});
289ef3aeadcSPatrick Venture }
290ef3aeadcSPatrick Venture 
writeMeta(ManagerInterface * mgr,std::span<const uint8_t> data)291067ece15SWilly Tu Resp writeMeta(ManagerInterface* mgr, std::span<const uint8_t> data)
2925c4b17b2SPatrick Venture {
2935c4b17b2SPatrick Venture     struct BmcBlobWriteMetaTx request;
294067ece15SWilly Tu     if (data.size() < sizeof(request))
295067ece15SWilly Tu     {
296067ece15SWilly Tu         return ipmi::responseReqDataLenInvalid();
297067ece15SWilly Tu     }
2985c4b17b2SPatrick Venture 
2995c4b17b2SPatrick Venture     /* Copy over the request. */
300067ece15SWilly Tu     std::memcpy(&request, data.data(), sizeof(request));
3015c4b17b2SPatrick Venture 
3025c4b17b2SPatrick Venture     /* Nothing really else to validate, we just copy those bytes. */
303067ece15SWilly Tu     data = data.subspan(sizeof(struct BmcBlobWriteMetaTx));
3045c4b17b2SPatrick Venture 
3055c4b17b2SPatrick Venture     /* Attempt to write the bytes. */
306067ece15SWilly Tu     if (!mgr->writeMeta(request.sessionId, request.offset,
307067ece15SWilly Tu                         std::vector<uint8_t>(data.begin(), data.end())))
3085c4b17b2SPatrick Venture     {
309067ece15SWilly Tu         return ipmi::responseUnspecifiedError();
3105c4b17b2SPatrick Venture     }
3115c4b17b2SPatrick Venture 
312067ece15SWilly Tu     return ipmi::responseSuccess(std::vector<uint8_t>{});
3135c4b17b2SPatrick Venture }
3145c4b17b2SPatrick Venture 
315ef3aeadcSPatrick Venture } // namespace blobs
316