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